Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1d0aba9
Initial commit for read_product function
Mar 19, 2026
376cc1f
adding returns for fits and asdf product types
Mar 19, 2026
4a7fcca
Updating read_product function
Mar 20, 2026
3e3b56a
Updating for cleaner asdf handling
Mar 20, 2026
7d8b427
Updating and adding log on failure
Mar 20, 2026
d45c0f7
Adding in description
Mar 24, 2026
beb09b5
Updating comments
Mar 24, 2026
1dc505e
and exception logic
Mar 30, 2026
587ccd6
Added in comments on package requirements for read_product functions
Apr 6, 2026
1bdb8a5
Updated imports to reflect only required packages
Apr 6, 2026
80238f6
Updating description
Apr 6, 2026
f883b8d
minor changes
Apr 9, 2026
66b4a6c
gwcs and lz4 packages do not need to be imported, they just need to b…
Apr 9, 2026
831baf4
Updating uri variable name to product_path be more general, as well a…
Apr 16, 2026
50c0ef3
Updating description
Apr 16, 2026
a8cb877
Updating import logic for read_product functions
Apr 17, 2026
a312ec2
Merge branch 'astropy:main' into ASB-30568_read-product-function
AlexReedy Apr 17, 2026
18fd33c
minor format change
Apr 17, 2026
4f99c05
Formatting Fixes
Apr 17, 2026
e6ad337
Changes import logic and checking to be cleaner
Apr 17, 2026
29d6ad4
Formatting
Apr 17, 2026
548414d
Formatting fix
Apr 17, 2026
cfeed72
Moving into observations class
Apr 17, 2026
909a45a
Formatting
Apr 17, 2026
a2556cc
Updating CHANGES.rst to reflect updates to read_product
Apr 17, 2026
91f322f
Adding fsspec to imports
Apr 17, 2026
8dd81d2
Formatting and typo
Apr 17, 2026
12ab349
removing print
Apr 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ mast
- The cloud dataset in ``Observations`` is now enabled by default if the ``boto3`` and ``botocore`` packages are installed. This
default can be overridden by setting the ``enable_cloud_dataset`` configuration option to False. [#3534]

- Adding in ability to read FITS and ASDF dataproducts to memory from s3:// using ``Observations.read_product()`` function. [#3561]


jplspec
^^^^^^^
Expand Down
64 changes: 64 additions & 0 deletions astroquery/mast/observations.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
import time
import os
from urllib.parse import quote
from importlib.metadata import version

import numpy as np
import astropy.units as u
from astropy.io import fits
import astropy.coordinates as coord
from requests import HTTPError
from astropy.table import Table, Row, vstack
Expand Down Expand Up @@ -44,6 +46,15 @@
'`~astroquery.mast.ObservationsClass.enable_cloud_dataset` method.'
)

asdf_packages = ["asdf", "s3fs", "fsspec", "lz4", "gwcs"]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does all of these really need to be checked here even as they are not directly been used? If asdf requires the whole list then these checks should be dealt with upstream in asdf itself.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been an ongoing question with the implementation. Required would be asdf, s3fs, fsspec for the function to work. for asdf specifically, lz4 seems to be the primary compression algorithm being used for asdf and gwcs is for the general.

I know that gwcs is in their test environment, and they also make calls to lz4 but I don't believe it's included when it's installed. I agree it should probably be upstream in asdf.

fits_packages = ['s3fs', 'fsspec']

try:
import asdf
import s3fs
except ImportError:
pass


@async_to_sync
class ObservationsClass(MastQueryWithLogin):
Expand Down Expand Up @@ -1203,6 +1214,59 @@ def get_unique_product_list(self, observations, *, batch_size=500):
log.info("To return all products, use `Observations.get_product_list`")
return unique_products

# TODO: Need to inlcude way to parse if it is a MAST on prem URL and handle the streaming of that
def read_product(self, product_path, read_as="auto", ignore_unrecognized=False):
"""
Read a product from Open S3 bucket to memory. Currently can handle FITS and ASDF product types.

Parameters
----------
product_path: str
URI to the product in open bucket.
read_as: str, optional
How to read the file. Currently only .fits and .asdf is supported by "auto". Defaults to "auto".
ignore_unrecognized: bool
Tells asdf.open() to include or ignore warnings from unrecognized asdf tags. Defaults to False

Returns
-------
object
FITS or ASDF object.
"""
if read_as == "auto":
if product_path.endswith(".fits"):
for package in fits_packages:
try:
version(package)
except ModuleNotFoundError:
log.debug(f"Missing Required Package: {package}")
return
try:
return fits.open(product_path, fsspec_kwargs={"anon": True})
except Exception as e:
log.exception(f"Failed to open FITS File: {product_path} {e}")

# Read logic for ASDF
elif product_path.endswith(".asdf"):
# Check all required modules are available
for package in asdf_packages:
try:
version(package)
except ModuleNotFoundError:
log.debug(f"Missing Required Package: {package}")
return

try:
fs = s3fs.S3FileSystem(anon=True)
with fs.open(product_path, 'rb') as s3_file:
af = asdf.open(s3_file, ignore_unrecognized_tag=ignore_unrecognized)
return af
except Exception as e:
log.exception(f"Failed to open ASD File: {product_path} {e}")
else:
log.error("Unsupported extension type")
return


@async_to_sync
class MastClass(MastQueryWithLogin):
Expand Down
Loading