Quick Start#

Authentication#

Grad300Client (aliased as Grad300) accepts either a username + password pair or a pre-obtained Bearer token.

from grad300_client import Grad300

# Authenticate with username / password (token acquired automatically)
client = Grad300(user="student@example.com", password="your-password")

# — or — supply a token directly
client = Grad300(token="eyJhb...")

You can also use it as a context manager so the underlying HTTP connection is closed automatically:

with Grad300(user="student@example.com", password="your-password") as client:
    table = client.query_source("Sun")

Querying scans#

All query methods return an astropy.table.Table whose columns mirror the ScanRecord fields (id, scan_type, file_name, source, ra, dec, date, …).

By source name#

# All scan types for "Sun"
table = client.query_source("Sun")

# Only TPI scans
tpi_table = client.query_source("Sun", scan_type="TPI")
print(tpi_table["file_name", "date"])

By partial filename#

# Matches any scan whose file_name contains "2025062"
table = client.query_scan_name("2025062")

By date range#

from datetime import datetime

march_scans = client.query_date_range(
    date_from=datetime(2026, 3, 1),
    date_to=datetime(2026, 3, 31, 23, 59, 59),
)

Combined filters#

table = client.query(
    scan_type="TPI",
    source="Jupiter",
    date_from=datetime(2026, 1, 1),
    max_results=50,
)

Downloading scans#

The download() family of methods returns different types depending on the scan type:

Scan type

In-memory return type

TPI

astropy.table.Table

Images, Spectrum, OnOff

astropy.io.fits.HDUList

In-memory download#

# From a table row obtained via a query
row = table[0]
data = client.download(row)

# TPI → astropy Table
if hasattr(data, "colnames"):
    print(data["Azimuth", "Elevation"])

# Other → HDUList
else:
    data.info()

Download to disk#

from pathlib import Path

path = client.download(row, destination_dir=Path("./downloads"))
print(f"Saved to {path}")

Download by scan ID or filename#

# By ID (must provide scan_type explicitly)
data = client.download_by_id(scan_type="TPI", scan_id=42)

# By exact filename (searches first, then downloads)
path = client.download_by_scan_name(
    "MyScan_2026.fits",
    destination_dir="./downloads",
)

Working with results as records#

If you prefer Python objects instead of an astropy Table, use the *_records variants:

records = client.query_records(source="Sun", scan_type="TPI")
for r in records:
    print(r.file_name, r.date, r.ra, r.dec)

Each item is a ScanRecord dataclass.