|
11 | 11 | import time |
12 | 12 | import os |
13 | 13 | from urllib.parse import quote |
| 14 | +from importlib.metadata import version |
14 | 15 |
|
15 | 16 | import numpy as np |
16 | 17 | import astropy.units as u |
| 18 | +from astropy.io import fits |
17 | 19 | import astropy.coordinates as coord |
18 | 20 | from requests import HTTPError |
19 | 21 | from astropy.table import Table, Row, vstack |
|
44 | 46 | '`~astroquery.mast.ObservationsClass.enable_cloud_dataset` method.' |
45 | 47 | ) |
46 | 48 |
|
| 49 | +asdf_packages = ["asdf", "s3fs", "fsspec", "lz4", "gwcs"] |
| 50 | +fits_packages = ['s3fs', 'fsspec'] |
| 51 | + |
| 52 | +try: |
| 53 | + import asdf |
| 54 | + import s3fs |
| 55 | +except ImportError: |
| 56 | + pass |
| 57 | + |
47 | 58 |
|
48 | 59 | @async_to_sync |
49 | 60 | class ObservationsClass(MastQueryWithLogin): |
@@ -1203,6 +1214,59 @@ def get_unique_product_list(self, observations, *, batch_size=500): |
1203 | 1214 | log.info("To return all products, use `Observations.get_product_list`") |
1204 | 1215 | return unique_products |
1205 | 1216 |
|
| 1217 | + # TODO: Need to inlcude way to parse if it is a MAST on prem URL and handle the streaming of that |
| 1218 | + def read_product(self, product_path, read_as="auto", ignore_unrecognized=False): |
| 1219 | + """ |
| 1220 | + Read a product from Open S3 bucket to memory. Currently can handle FITS and ASDF product types. |
| 1221 | +
|
| 1222 | + Parameters |
| 1223 | + ---------- |
| 1224 | + product_path: str |
| 1225 | + URI to the product in open bucket. |
| 1226 | + read_as: str, optional |
| 1227 | + How to read the file. Currently only .fits and .asdf is supported by "auto". Defaults to "auto". |
| 1228 | + ignore_unrecognized: bool |
| 1229 | + Tells asdf.open() to include or ignore warnings from unrecognized asdf tags. Defaults to False |
| 1230 | +
|
| 1231 | + Returns |
| 1232 | + ------- |
| 1233 | + object |
| 1234 | + FITS or ASDF object. |
| 1235 | + """ |
| 1236 | + if read_as == "auto": |
| 1237 | + if product_path.endswith(".fits"): |
| 1238 | + for package in fits_packages: |
| 1239 | + try: |
| 1240 | + version(package) |
| 1241 | + except ModuleNotFoundError: |
| 1242 | + log.debug(f"Missing Required Package: {package}") |
| 1243 | + return |
| 1244 | + try: |
| 1245 | + return fits.open(product_path, fsspec_kwargs={"anon": True}) |
| 1246 | + except Exception as e: |
| 1247 | + log.exception(f"Failed to open FITS File: {product_path} {e}") |
| 1248 | + |
| 1249 | + # Read logic for ASDF |
| 1250 | + elif product_path.endswith(".asdf"): |
| 1251 | + # Check all required modules are available |
| 1252 | + for package in asdf_packages: |
| 1253 | + try: |
| 1254 | + version(package) |
| 1255 | + except ModuleNotFoundError: |
| 1256 | + log.debug(f"Missing Required Package: {package}") |
| 1257 | + return |
| 1258 | + |
| 1259 | + try: |
| 1260 | + fs = s3fs.S3FileSystem(anon=True) |
| 1261 | + with fs.open(product_path, 'rb') as s3_file: |
| 1262 | + af = asdf.open(s3_file, ignore_unrecognized_tag=ignore_unrecognized) |
| 1263 | + return af |
| 1264 | + except Exception as e: |
| 1265 | + log.exception(f"Failed to open ASD File: {product_path} {e}") |
| 1266 | + else: |
| 1267 | + log.error("Unsupported extension type") |
| 1268 | + return |
| 1269 | + |
1206 | 1270 |
|
1207 | 1271 | @async_to_sync |
1208 | 1272 | class MastClass(MastQueryWithLogin): |
|
0 commit comments