Skip to content

Merge pull request #918 from CLIMADA-project/feature/restructure_fitf…

Jenkins - WCR / Tests / Declarative: Post Actions failed Nov 7, 2024 in 0s

climada.test.test_nightlight.TestNightlight.test_download_nl_files failed

Send us feedback

Details

climada.test.test_nightlight.TestNightlight.test_download_nl_files

RuntimeError: Download failed. Please check the network connection and whether filenames are still valid.
Stack trace
self = <urllib3.response.HTTPResponse object at 0x7fd16b411c30>

    @contextmanager
    def _error_catcher(self) -> typing.Generator[None, None, None]:
        """
        Catch low-level python exceptions, instead re-raising urllib3
        variants, so that low-level exceptions are not leaked in the
        high-level api.
    
        On exit, release the connection back to the pool.
        """
        clean_exit = False
    
        try:
            try:
>               yield

../../../miniforge3/envs/climada_env/lib/python3.11/site-packages/urllib3/response.py:748: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <urllib3.response.HTTPResponse object at 0x7fd16b411c30>, amt = 1024

    def _raw_read(
        self,
        amt: int | None = None,
        *,
        read1: bool = False,
    ) -> bytes:
        """
        Reads `amt` of bytes from the socket.
        """
        if self._fp is None:
            return None  # type: ignore[return-value]
    
        fp_closed = getattr(self._fp, "closed", False)
    
        with self._error_catcher():
            data = self._fp_read(amt, read1=read1) if not fp_closed else b""
            if amt is not None and amt != 0 and not data:
                # Platform-specific: Buggy versions of Python.
                # Close the connection when no data is returned
                #
                # This is redundant to what httplib/http.client _should_
                # already do.  However, versions of python released before
                # December 15, 2012 (http://bugs.python.org/issue16298) do
                # not properly close the connection in all cases. There is
                # no harm in redundantly calling close.
                self._fp.close()
                if (
                    self.enforce_content_length
                    and self.length_remaining is not None
                    and self.length_remaining != 0
                ):
                    # This is an edge case that httplib failed to cover due
                    # to concerns of backward compatibility. We're
                    # addressing it here to make sure IncompleteRead is
                    # raised during streaming, so all calls with incorrect
                    # Content-Length are caught.
>                   raise IncompleteRead(self._fp_bytes_read, self.length_remaining)
E                   urllib3.exceptions.IncompleteRead: IncompleteRead(9600260 bytes read, 12288121 more expected)

../../../miniforge3/envs/climada_env/lib/python3.11/site-packages/urllib3/response.py:894: IncompleteRead

The above exception was the direct cause of the following exception:

    def generate():
        # Special case for urllib3.
        if hasattr(self.raw, "stream"):
            try:
>               yield from self.raw.stream(chunk_size, decode_content=True)

../../../miniforge3/envs/climada_env/lib/python3.11/site-packages/requests/models.py:820: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../miniforge3/envs/climada_env/lib/python3.11/site-packages/urllib3/response.py:1060: in stream
    data = self.read(amt=amt, decode_content=decode_content)
../../../miniforge3/envs/climada_env/lib/python3.11/site-packages/urllib3/response.py:977: in read
    data = self._raw_read(amt)
../../../miniforge3/envs/climada_env/lib/python3.11/site-packages/urllib3/response.py:872: in _raw_read
    with self._error_catcher():
../../../miniforge3/envs/climada_env/lib/python3.11/contextlib.py:155: in __exit__
    self.gen.throw(typ, value, traceback)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <urllib3.response.HTTPResponse object at 0x7fd16b411c30>

    @contextmanager
    def _error_catcher(self) -> typing.Generator[None, None, None]:
        """
        Catch low-level python exceptions, instead re-raising urllib3
        variants, so that low-level exceptions are not leaked in the
        high-level api.
    
        On exit, release the connection back to the pool.
        """
        clean_exit = False
    
        try:
            try:
                yield
    
            except SocketTimeout as e:
                # FIXME: Ideally we'd like to include the url in the ReadTimeoutError but
                # there is yet no clean way to get at it from this context.
                raise ReadTimeoutError(self._pool, None, "Read timed out.") from e  # type: ignore[arg-type]
    
            except BaseSSLError as e:
                # FIXME: Is there a better way to differentiate between SSLErrors?
                if "read operation timed out" not in str(e):
                    # SSL errors related to framing/MAC get wrapped and reraised here
                    raise SSLError(e) from e
    
                raise ReadTimeoutError(self._pool, None, "Read timed out.") from e  # type: ignore[arg-type]
    
            except IncompleteRead as e:
                if (
                    e.expected is not None
                    and e.partial is not None
                    and e.expected == -e.partial
                ):
                    arg = "Response may not contain content."
                else:
                    arg = f"Connection broken: {e!r}"
>               raise ProtocolError(arg, e) from e
E               urllib3.exceptions.ProtocolError: ('Connection broken: IncompleteRead(9600260 bytes read, 12288121 more expected)', IncompleteRead(9600260 bytes read, 12288121 more expected))

../../../miniforge3/envs/climada_env/lib/python3.11/site-packages/urllib3/response.py:772: ProtocolError

During handling of the above exception, another exception occurred:

req_files = array([1, 0, 0, 0, 0, 0, 0, 0])
files_exist = array([0, 1, 1, 1, 1, 1, 1, 1]), dwnl_path = '/tmp/tmpqqys8q3w'
year = 2016

    def download_nl_files(
        req_files=np.ones(
            len(BM_FILENAMES),
        ),
        files_exist=np.zeros(
            len(BM_FILENAMES),
        ),
        dwnl_path=SYSTEM_DIR,
        year=2016,
    ):
        """Attempts to download nightlight files from NASA webpage.
    
        Parameters
        ----------
        req_files : numpy array, optional
            Boolean array which indicates the files required (0-> skip, 1-> download).
                The default is np.ones(len(BM_FILENAMES),).
        files_exist : numpy array, optional
            Boolean array which indicates if the files already
                exist locally and should not be downloaded (0-> download, 1-> skip).
                The default is np.zeros(len(BM_FILENAMES),).
        dwnl_path : str or path, optional
            Download directory path. The default is SYSTEM_DIR.
        year : int, optional
            Data year to be downloaded. The default is 2016.
    
        Raises
        ------
        ValueError
        RuntimeError
    
        Returns
        -------
        dwnl_path : str or path
            Download directory path.
        """
    
        if (len(req_files) != len(files_exist)) or (len(req_files) != len(BM_FILENAMES)):
            raise ValueError(
                "The given arguments are invalid. req_files and "
                "files_exist must both be as long as there are files to download"
                " (" + str(len(BM_FILENAMES)) + ")."
            )
        if not Path(dwnl_path).is_dir():
            raise ValueError(f"The folder {dwnl_path} does not exist. Operation aborted.")
        if np.all(req_files == files_exist):
            LOGGER.debug("All required files already exist. No downloads necessary.")
            return dwnl_path
        try:
            for num_files in range(0, np.count_nonzero(BM_FILENAMES)):
                if req_files[num_files] == 0 or files_exist[num_files] == 1:
                    continue  # file already available or not required
                path_check = False
                # loop through different possible URLs defined in CONFIG:
                value_err = None
                for url in CONFIG.exposures.litpop.nightlights.nasa_sites.list():
                    try:  # control for ValueError due to wrong URL
                        curr_file = url.str() + BM_FILENAMES[num_files] % (year)
                        LOGGER.info("Attempting to download file from %s", curr_file)
>                       path_check = download_file(curr_file, download_dir=dwnl_path)

climada/entity/exposures/litpop/nightlight.py:363: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
climada/util/files_handler.py:108: in download_file
    for data in tqdm(
../../../miniforge3/envs/climada_env/lib/python3.11/site-packages/tqdm/std.py:1181: in __iter__
    for obj in iterable:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    def generate():
        # Special case for urllib3.
        if hasattr(self.raw, "stream"):
            try:
                yield from self.raw.stream(chunk_size, decode_content=True)
            except ProtocolError as e:
>               raise ChunkedEncodingError(e)
E               requests.exceptions.ChunkedEncodingError: ('Connection broken: IncompleteRead(9600260 bytes read, 12288121 more expected)', IncompleteRead(9600260 bytes read, 12288121 more expected))

../../../miniforge3/envs/climada_env/lib/python3.11/site-packages/requests/models.py:822: ChunkedEncodingError

The above exception was the direct cause of the following exception:

self = <climada.test.test_nightlight.TestNightlight testMethod=test_download_nl_files>

    def test_download_nl_files(self):
        """Test that BlackMarble GeoTiff files are downloaded."""
    
        # Test Raises
        temp_dir = TemporaryDirectory()
        with self.assertRaises(ValueError) as cm:
            nightlight.download_nl_files(
                req_files=np.ones(5), files_exist=np.zeros(4), dwnl_path=temp_dir.name
            )
        self.assertEqual(
            "The given arguments are invalid. req_files and "
            "files_exist must both be as long as there are files to download "
            "(8).",
            str(cm.exception),
        )
        with self.assertRaises(ValueError) as cm:
            nightlight.download_nl_files(dwnl_path="not a folder")
        self.assertEqual(
            "The folder not a folder does not exist. Operation aborted.",
            str(cm.exception),
        )
        # Test logger
        with self.assertLogs(
            "climada.entity.exposures.litpop.nightlight", level="DEBUG"
        ) as cm:
            dwl_path = nightlight.download_nl_files(
                req_files=np.ones(
                    len(BM_FILENAMES),
                ),
                files_exist=np.ones(
                    len(BM_FILENAMES),
                ),
                dwnl_path=temp_dir.name,
                year=2016,
            )
            self.assertIn(
                "All required files already exist. No downloads necessary.",
                cm.output[0],
            )
    
        # Test download
        with self.assertLogs(
            "climada.entity.exposures.litpop.nightlight", level="DEBUG"
        ) as cm:
>           dwl_path = nightlight.download_nl_files(
                req_files=np.array([1, 0, 0, 0, 0, 0, 0, 0]),
                files_exist=np.array([0, 1, 1, 1, 1, 1, 1, 1]),
                dwnl_path=temp_dir.name,
            )

climada/test/test_nightlight.py:193: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

req_files = array([1, 0, 0, 0, 0, 0, 0, 0])
files_exist = array([0, 1, 1, 1, 1, 1, 1, 1]), dwnl_path = '/tmp/tmpqqys8q3w'
year = 2016

    def download_nl_files(
        req_files=np.ones(
            len(BM_FILENAMES),
        ),
        files_exist=np.zeros(
            len(BM_FILENAMES),
        ),
        dwnl_path=SYSTEM_DIR,
        year=2016,
    ):
        """Attempts to download nightlight files from NASA webpage.
    
        Parameters
        ----------
        req_files : numpy array, optional
            Boolean array which indicates the files required (0-> skip, 1-> download).
                The default is np.ones(len(BM_FILENAMES),).
        files_exist : numpy array, optional
            Boolean array which indicates if the files already
                exist locally and should not be downloaded (0-> download, 1-> skip).
                The default is np.zeros(len(BM_FILENAMES),).
        dwnl_path : str or path, optional
            Download directory path. The default is SYSTEM_DIR.
        year : int, optional
            Data year to be downloaded. The default is 2016.
    
        Raises
        ------
        ValueError
        RuntimeError
    
        Returns
        -------
        dwnl_path : str or path
            Download directory path.
        """
    
        if (len(req_files) != len(files_exist)) or (len(req_files) != len(BM_FILENAMES)):
            raise ValueError(
                "The given arguments are invalid. req_files and "
                "files_exist must both be as long as there are files to download"
                " (" + str(len(BM_FILENAMES)) + ")."
            )
        if not Path(dwnl_path).is_dir():
            raise ValueError(f"The folder {dwnl_path} does not exist. Operation aborted.")
        if np.all(req_files == files_exist):
            LOGGER.debug("All required files already exist. No downloads necessary.")
            return dwnl_path
        try:
            for num_files in range(0, np.count_nonzero(BM_FILENAMES)):
                if req_files[num_files] == 0 or files_exist[num_files] == 1:
                    continue  # file already available or not required
                path_check = False
                # loop through different possible URLs defined in CONFIG:
                value_err = None
                for url in CONFIG.exposures.litpop.nightlights.nasa_sites.list():
                    try:  # control for ValueError due to wrong URL
                        curr_file = url.str() + BM_FILENAMES[num_files] % (year)
                        LOGGER.info("Attempting to download file from %s", curr_file)
                        path_check = download_file(curr_file, download_dir=dwnl_path)
                        break  # leave loop if sucessful
                    except ValueError as err:
                        value_err = err
                if path_check:  # download succesful
                    continue
                if value_err:
                    raise ValueError(
                        "Download failed,"
                        " check URLs inCONFIG.exposures.litpop.nightlights.nasa_sites!\n"
                        f" Last error message:\n {value_err.args[0]}"
                    )
                else:
                    raise ValueError(
                        "Download failed, file not found and no nasa sites configured,"
                        " check URLs in CONFIG.exposures.litpop.nightlights.nasa_sites!"
                    )
        except Exception as exc:
>           raise RuntimeError(
                "Download failed. Please check the network "
                "connection and whether filenames are still valid."
            ) from exc
E           RuntimeError: Download failed. Please check the network connection and whether filenames are still valid.

climada/entity/exposures/litpop/nightlight.py:381: RuntimeError