Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,20 @@ $ ialirt-data-access --url <url> ialirt-log-query --year <year> --doy <doy> --in

### Query / Search for packets

Find all files from a given year, day of year, hour, minute, and second.
Two mutually exclusive query modes are supported.

**Individual params mode** — query by partial datetime (year and doy required):

```bash
$ ialirt-data-access --url <url> ialirt-packet-query --year <year> --doy <doy> [--hh <hour>] [--mm <minute>] [--ss <second>]
```

**UTC range mode** — query by ISO 8601 time range (time_utc_start required):

```bash
$ ialirt-data-access --url <url> ialirt-packet-query --time_utc_start <YYYY-MM-DDTHH:MM:SS> [--time_utc_end <YYYY-MM-DDTHH:MM:SS>]
```

### Query / Search for archive CDF files

Find all archive CDF files, optionally filtered by year, month, and day. All parameters are optional; version defaults to 1.
Expand Down
35 changes: 31 additions & 4 deletions ialirt_data_access/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
ialirt-data-access --url <url> ialirt-packet-query
--year 2025 --doy 148 --hh 16 --mm 24

ialirt-data-access --url <url> ialirt-packet-query
--time_utc_start 2025-10-29T18:55:02 --time_utc_end 2025-10-29T19:05:00

ialirt-data-access --url <url> ialirt-archive-query
--year 2024 --month 05 --day 21 --version 1

Expand Down Expand Up @@ -79,7 +82,8 @@ def _packet_query_parser(args: argparse.Namespace):
Parameters
----------
args : argparse.Namespace
Parsed arguments including year, doy, hh, mm, ss.
Parsed arguments including year, doy, hh, mm, ss,
time_utc_start, time_utc_end.

Returns
-------
Expand All @@ -91,6 +95,8 @@ def _packet_query_parser(args: argparse.Namespace):
"hh": args.hh,
"mm": args.mm,
"ss": args.ss,
"time_utc_start": args.time_utc_start,
"time_utc_end": args.time_utc_end,
}
# Remove any keys with None values.
query_params = {k: v for k, v in query_params.items() if v is not None}
Expand Down Expand Up @@ -179,7 +185,7 @@ def _data_product_query_parser(args: argparse.Namespace):
print(f"Error: {e}")


def main():
def main(): # noqa: PLR0915
"""Parse the command line arguments.

Run the command line interface to the I-ALiRT Data Access API.
Expand Down Expand Up @@ -246,10 +252,17 @@ def main():
# Packet query command
packet_query_parser = subparsers.add_parser("ialirt-packet-query")
packet_query_parser.add_argument(
"--year", type=str, required=True, help="Year of the packet (e.g., 2025)."
"--year",
type=str,
required=False,
help="Year of the packet (e.g., 2025). Required for individual params mode.",
)
packet_query_parser.add_argument(
"--doy", type=str, required=True, help="Day of year of the packet (e.g., 148)."
"--doy",
type=str,
required=False,
help="Day of year of the packet (e.g., 148). "
"Required for individual params mode.",
)
packet_query_parser.add_argument(
"--hh", type=str, required=False, help="Hour (0 to 23)."
Expand All @@ -260,6 +273,20 @@ def main():
packet_query_parser.add_argument(
"--ss", type=str, required=False, help="Second (0 to 59)."
)
packet_query_parser.add_argument(
"--time_utc_start",
type=str,
required=False,
help="Start of UTC time range (ISO 8601, e.g., 2025-10-29T18:55:02). "
"Required for UTC range mode.",
)
packet_query_parser.add_argument(
"--time_utc_end",
type=str,
required=False,
help="End of UTC time range (ISO 8601, e.g., 2025-10-29T19:05:00). "
"Optional in UTC range mode.",
)
packet_query_parser.set_defaults(func=_packet_query_parser)

# Archive query command
Expand Down
68 changes: 48 additions & 20 deletions ialirt_data_access/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,44 +132,72 @@ def log_query(*, year: str, doy: str, instance: str) -> list[str]:
return items


def packet_query(
def packet_query( # noqa: PLR0913
*,
year: str,
doy: str,
year: Optional[str] = None,
doy: Optional[str] = None,
hh: Optional[str] = None,
mm: Optional[str] = None,
ss: Optional[str] = None,
time_utc_start: Optional[str] = None,
time_utc_end: Optional[str] = None,
) -> list[str]:
"""Query the I-ALiRT packet files by partial datetime.
"""Query the I-ALiRT packet files.

Two mutually exclusive query modes are supported:

UTC range mode — strict ISO 8601 format ``YYYY-MM-DDTHH:MM:SS``.
``time_utc_start`` is required; ``time_utc_end`` is optional.

Individual params mode — partial time specification
(``year``, ``doy``[, ``hh``[, ``mm``[, ``ss``]]]).
At minimum, ``year`` and ``doy`` must be provided.

Parameters
----------
year : str
Year, e.g., '2025'
doy : str
Day of year, e.g., '148'
year : str, optional
Year, e.g., '2025'. Required for individual params mode.
doy : str, optional
Day of year, e.g., '148'. Required for individual params mode.
hh : str, optional
Hour of day, 0 to 23
Hour of day, 0 to 23.
mm : str, optional
Minute, 0 to 59
Minute, 0 to 59.
ss : str, optional
Second, 0 to 59
Second, 0 to 59.
time_utc_start : str, optional
Start of UTC time range (ISO 8601, e.g., '2025-10-29T18:55:02').
Required for UTC range mode.
time_utc_end : str, optional
End of UTC time range (ISO 8601). Optional in UTC range mode.

Returns
-------
list of str
Matching packet file names.
"""
query_params = {"year": year, "doy": doy}

if hh:
query_params["hh"] = hh
if mm:
query_params["mm"] = mm
if ss:
query_params["ss"] = ss
utc_params = {
k: v
for k, v in {
"time_utc_start": time_utc_start,
"time_utc_end": time_utc_end,
}.items()
if v is not None
}

_validate_query_params(**query_params)
if utc_params:
query_params: dict = {"time_utc_start": time_utc_start}
if time_utc_end:
query_params["time_utc_end"] = time_utc_end
else:
query_params = {"year": year, "doy": doy}
if hh:
query_params["hh"] = hh
if mm:
query_params["mm"] = mm
if ss:
query_params["ss"] = ss
_validate_query_params(**query_params)

url = f"{ialirt_data_access.config['DATA_ACCESS_URL']}"
url += f"/ialirt-packet-query?{urlencode(query_params)}"
Expand Down
38 changes: 38 additions & 0 deletions tests/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,44 @@ def test_packet_query(mock_urlopen: unittest.mock.MagicMock):
assert called_url == expected_url_encoded


def test_packet_query_utc_range(mock_urlopen: unittest.mock.MagicMock):
"""Test packet_query in UTC range mode."""
filename = "iois_1_packets_2025_302_18_55_02"
_set_mock_data(mock_urlopen, json.dumps([filename]).encode("utf-8"))

response = ialirt_data_access.packet_query(
time_utc_start="2025-10-29T18:55:02",
time_utc_end="2025-10-29T19:05:00",
)
assert response == [filename]

mock_urlopen.assert_called_once()
urlopen_call = mock_urlopen.mock_calls[0].args[0]
called_url = urlopen_call.full_url
expected_url_encoded = "https://ialirt.test.com/ialirt-packet-query?" + urlencode(
{
"time_utc_start": "2025-10-29T18:55:02",
"time_utc_end": "2025-10-29T19:05:00",
}
)
assert called_url == expected_url_encoded


def test_packet_query_utc_start_only(mock_urlopen: unittest.mock.MagicMock):
"""Test packet_query in UTC range mode with only time_utc_start."""
filename = "iois_1_packets_2025_302_18_55_02"
_set_mock_data(mock_urlopen, json.dumps([filename]).encode("utf-8"))

response = ialirt_data_access.packet_query(time_utc_start="2025-10-29T18:55:02")
assert response == [filename]

urlopen_call = mock_urlopen.mock_calls[0].args[0]
expected_url_encoded = "https://ialirt.test.com/ialirt-packet-query?" + urlencode(
{"time_utc_start": "2025-10-29T18:55:02"}
)
assert urlopen_call.full_url == expected_url_encoded


def test_query_bad_params(mock_urlopen: unittest.mock.MagicMock):
"""Test a call to the Query API that has invalid parameters."""
with pytest.raises(
Expand Down