diff --git a/hips/tiles/fetch.py b/hips/tiles/fetch.py index 0382dd5..5d1e246 100644 --- a/hips/tiles/fetch.py +++ b/hips/tiles/fetch.py @@ -81,7 +81,11 @@ def fetch_tiles(tile_metas: List[HipsTileMeta], hips_survey: HipsSurveyPropertie tiles = [] for idx, response in enumerate(response_all): - tiles.append(HipsTile(tile_metas[idx], response['raw_data'])) + try: + response['raw_data'] + tiles.append(HipsTile(tile_metas[idx], response['raw_data'])) + except KeyError: + tiles.append(HipsTile(tile_metas[idx], b'', is_missing=True)) return tiles @@ -92,9 +96,11 @@ def fetch_tile_urllib(url: str, timeout: float) -> dict: with urllib.request.urlopen(url, timeout=timeout) as conn: return {'raw_data': conn.read(), 'url': url} except urllib.error.HTTPError as error: + # If the tile is missing, enable the `is_missing` flag in HipsTile. if error.code == 404: - error.msg = f'Tile not found at:\n{url}' - raise + return {'is_missing': True} + # error.msg = f'Tile not found at:\n{url}' + # raise except urllib.error.URLError as error: if isinstance(error.reason, socket.timeout): raise TimeoutError(f'The server timed out while fetching the tile at:\n{url}') diff --git a/hips/tiles/tile.py b/hips/tiles/tile.py index 1fb362c..ba10995 100644 --- a/hips/tiles/tile.py +++ b/hips/tiles/tile.py @@ -154,6 +154,8 @@ class HipsTile: Metadata of HiPS tile raw_data : `bytes` Raw data (copy of bytes from file) + is_missing : `bool` + To check whether the tile is missing or not Examples -------- @@ -175,9 +177,10 @@ class HipsTile: int16 """ - def __init__(self, meta: HipsTileMeta, raw_data: bytes) -> None: + def __init__(self, meta: HipsTileMeta, raw_data: bytes, is_missing: bool = False) -> None: self.meta = meta self.raw_data = raw_data + self.is_missing = is_missing self._data = None def __eq__(self, other: "HipsTile") -> bool: @@ -259,8 +262,10 @@ def data(self) -> np.ndarray: See the `to_numpy` function. """ - if self._data is None: + if self._data is None and not self.is_missing: self._data = self.to_numpy(self.raw_data, self.meta.file_format) + elif self.is_missing: + self._data = np.zeros((compute_image_shape(self.meta.width, self.meta.width, self.meta.file_format))) return self._data @@ -295,6 +300,7 @@ def to_numpy(raw_data: bytes, fmt: str) -> np.ndarray: elif fmt in {"jpg", "png"}: with Image.open(bio) as image: data = np.array(image) + # Flip tile to be consistent with FITS orientation data = np.flipud(data) else: @@ -316,6 +322,7 @@ def read(cls, meta: HipsTileMeta, filename: str = None) -> "HipsTile": filename : str Filename """ + # TODO: Handle case for files that don't exist. raw_data = Path(filename).read_bytes() return cls(meta, raw_data) @@ -330,6 +337,7 @@ def fetch(cls, meta: HipsTileMeta, url: str) -> "HipsTile": url : str URL containing HiPS tile """ + # TODO: Add timeout and error handling. with urllib.request.urlopen(url) as response: raw_data = response.read()