Skip to content
Open
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
3 changes: 2 additions & 1 deletion imap_data_access/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,8 @@ def add_query_args(subparser: ArgumentParser) -> None:
required=False,
help="Version of the product in the format 'v001'."
" Must have one other parameter to run."
" Passing 'latest' will return latest version of a file per start_date",
" Passing 'latest' will return latest version of a file "
"per dataset (instrument, data_level, descriptor) and day or repointing",
)
subparser.add_argument(
"--extension", type=str, required=False, help="File extension (cdf, pkts)"
Expand Down
30 changes: 16 additions & 14 deletions imap_data_access/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,22 +387,24 @@ def query(

# if latest version was included in search then filter returned query for largest.
if (version == "latest") and items:
latest_per_day = {}

def get_key(file_entry):
return (
file_entry["instrument"],
file_entry["descriptor"],
file_entry.get("data_level"),
file_entry["start_date"],
file_entry.get("repointing"),
)
Comment thread
tmplummer marked this conversation as resolved.

latest_files = {}
for item in items:
day = item["start_date"]
version_num = int(item["version"][1:4])
# filter by highest version per day
if (day not in latest_per_day) or (
version_num > latest_per_day[day]["_version_num"]
key = get_key(item)
if (key not in latest_files) or (
item["version"] > latest_files[key]["version"]
):
# add extra field to identify version number
latest_per_day[day] = {**item, "_version_num": version_num}
# remove the extra field
items = [
{k: version for k, version in val.items() if k != "_version_num"}
for val in latest_per_day.values()
]

latest_files[key] = item
items = list(latest_files.values())
return items


Expand Down
184 changes: 184 additions & 0 deletions tests/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,190 @@ def test_query(mock_send_request, query_params: dict):
assert called_url == expected_url_encoded


glows_l3e_hi_repoint1 = {
"instrument": "glows",
"data_level": "l3e",
"descriptor": "survival-probability-hi-45",
"version": "v001",
"start_date": "20250101",
"repointing": 1,
}

glows_l3e_hi_repoint2_v1 = {
"instrument": "glows",
"data_level": "l3e",
"descriptor": "survival-probability-hi-45",
"version": "v001",
"start_date": "20250101",
"repointing": 2,
}

glows_l3e_hi_repoint2_v2 = {
"instrument": "glows",
"data_level": "l3e",
"descriptor": "survival-probability-hi-45",
"version": "v002",
"start_date": "20250101",
"repointing": 2,
}

swapi_l3b_day1_v2 = {
"instrument": "swapi",
"data_level": "l3b",
"descriptor": "combined",
"version": "v002",
"start_date": "20250101",
"repointing": None,
}
swapi_l3b_day2_v2 = {
"instrument": "swapi",
"data_level": "l3b",
"descriptor": "combined",
"version": "v002",
"start_date": "20250102",
"repointing": None,
}
swapi_l3b_day2_v3 = {
"instrument": "swapi",
"data_level": "l3b",
"descriptor": "combined",
"version": "v003",
"start_date": "20250102",
"repointing": None,
}

hi_l1b_45_day1_v1 = {
"instrument": "hi",
"data_level": "l1b",
"descriptor": "45pset",
"version": "v001",
"start_date": "20250101",
"repointing": None,
}

lo_l1c_45_day1_v1 = {
"instrument": "lo",
"data_level": "l1c",
"descriptor": "45pset",
"version": "v001",
"start_date": "20250101",
"repointing": None,
}

hi_l1c_45_day1_v1 = {
"instrument": "hi",
"data_level": "l1c",
"descriptor": "45pset",
"version": "v001",
"start_date": "20250101",
"repointing": None,
}

hi_l1c_90_day1_v1 = {
"instrument": "hi",
"data_level": "l1c",
"descriptor": "90pset",
"version": "v001",
"start_date": "20250101",
"repointing": None,
}

codice_ancillary_day1_v1 = {
"instrument": "codice",
"descriptor": "geometric-factor",
"version": "v001",
"start_date": "20250101",
}

codice_ancillary_day1_v2 = {
"instrument": "codice",
"descriptor": "geometric-factor",
"version": "v002",
"start_date": "20250101",
}

codice_ancillary_day2_v1 = {
"instrument": "codice",
"descriptor": "geometric-factor",
"version": "v001",
"start_date": "20250102",
}


@pytest.mark.parametrize(
("query_params", "query_results", "expected_filtered_results"),
[
(
{"instrument": "glows", "data_level": "l3e", "version": "latest"},
[glows_l3e_hi_repoint1, glows_l3e_hi_repoint2_v1, glows_l3e_hi_repoint2_v2],
[glows_l3e_hi_repoint1, glows_l3e_hi_repoint2_v2],
),
(
{"instrument": "glows", "data_level": "l3e"},
[glows_l3e_hi_repoint1, glows_l3e_hi_repoint2_v1, glows_l3e_hi_repoint2_v2],
[glows_l3e_hi_repoint1, glows_l3e_hi_repoint2_v1, glows_l3e_hi_repoint2_v2],
),
(
{"instrument": "swapi", "data_level": "l3b", "version": "latest"},
[swapi_l3b_day1_v2, swapi_l3b_day2_v2, swapi_l3b_day2_v3],
[swapi_l3b_day1_v2, swapi_l3b_day2_v3],
),
(
{"start_date": "20250101", "end_date": "20250103", "version": "latest"},
[
hi_l1b_45_day1_v1,
lo_l1c_45_day1_v1,
hi_l1c_45_day1_v1,
hi_l1c_90_day1_v1,
],
[
hi_l1b_45_day1_v1,
lo_l1c_45_day1_v1,
hi_l1c_45_day1_v1,
hi_l1c_90_day1_v1,
],
),
(
{"table": "ancillary", "instrument": "codice", "version": "latest"},
[
codice_ancillary_day1_v1,
codice_ancillary_day1_v2,
codice_ancillary_day2_v1,
],
[
codice_ancillary_day1_v2,
codice_ancillary_day2_v1,
],
),
],
)
def test_query_with_version_latest(
mock_send_request,
query_params: dict,
query_results: list[dict],
expected_filtered_results: list[dict],
):
"""Test Query version latest filtering.

Parameters
----------
mock_send_request : unittest.mock.MagicMock
Mock object for requests.Session
query_params : dict
Dictionary of key/value pairs that set the query parameters
query_results : list[dict]
Result returned by query API call
expected_filtered_results : list[dict]
The expected results after latest version filtering
"""
mock_response = MagicMock()
mock_response.json.return_value = query_results
mock_send_request.return_value = mock_response

response = imap_data_access.query(**query_params)
assert response == expected_filtered_results


def test_query_no_params(mock_send_request):
"""Test a call to the Query API that has no parameters.
Parameters
Expand Down
Loading