Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unit tests for gpm_api.io #8

Merged
merged 39 commits into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
e6bb56e
Unit tests for gpm_api.io.checks, run coverage on pytest
evanjt Jul 19, 2023
5b642a6
Use black, remove bbox check, move bbox test to geospatial test for f…
evanjt Jul 20, 2023
1e79137
Cast np datetime [ns] to [us]
evanjt Jul 20, 2023
8670b55
Add io/directories tests, modify replace() in curl path constructor a…
evanjt Jul 24, 2023
fb0d33a
Mock ftplib, add tests to disk, download, info
evanjt Jul 24, 2023
3542f84
Modify checks to use os.path.sep to cater for Windows paths
evanjt Jul 24, 2023
e60baec
Add type hint exception for Python 3.8
evanjt Jul 24, 2023
4a7e561
Apply sed command to conftest.py for 3.8 type hints
evanjt Jul 24, 2023
c36f2fe
Modify type hints to be compatible with Python 3.8
evanjt Jul 25, 2023
9bac278
Remove type annotation hack for python 3.8
evanjt Jul 25, 2023
4cdf6f3
test _download_files
evanjt Aug 9, 2023
0700e40
Add test for file completeness
evanjt Aug 9, 2023
d5271d1
Add filter tests
evanjt Aug 10, 2023
45686b5
Add filter unit tests
evanjt Aug 10, 2023
827ff64
Merge branch 'ghiggi:main' into add_io_tests
evanjt Aug 11, 2023
6e4eda0
Merge branch 'add_io_tests' of github.com:EPFL-ENAC/gpm_api into add_…
evanjt Aug 11, 2023
db103ff
Update tests to reflect branch changes
evanjt Aug 11, 2023
23b660a
Add io tests: download_files, convert_pps_to_disk_filepaths, flatten_…
evanjt Aug 11, 2023
97997aa
Add pps tests
evanjt Aug 11, 2023
b0be78a
Add data integrity tests and static filepath fixtures
evanjt Aug 16, 2023
1f2b2af
Mock the user configuration function as to user in-memory configurati…
evanjt Aug 16, 2023
86e4aee
Disable check_start_end_time on empty end_time due to testing inconsi…
evanjt Aug 16, 2023
1b75aae
Remove system specific paths
evanjt Aug 16, 2023
a4e3552
Modify path to os library
evanjt Aug 16, 2023
eca5f20
Fix windows paths
evanjt Aug 16, 2023
49b55c7
Replace : character to - for windows path compatibility
evanjt Aug 16, 2023
2549c72
Merge branch 'ghiggi:main' into add_io_tests
evanjt Aug 18, 2023
54c1e81
Add tests to validate future date errors if using None end_time in fi…
evanjt Aug 21, 2023
c0358e5
Update comment, removing TODO
evanjt Aug 21, 2023
21375e7
Update docstring explaining defaults in filter_by_time
evanjt Aug 21, 2023
8827b5e
Remove redundant auth fixtures from conftest, replace with values in …
evanjt Aug 31, 2023
106d18e
Replace ns with seconds
evanjt Aug 31, 2023
36dacd2
Update gpm_api/tests/io/test_download.py
ghiggi Sep 5, 2023
3921c02
Revert to seconds
evanjt Sep 5, 2023
733b76d
Check timezone, throw error if given and is not UTC
evanjt Sep 5, 2023
8cb2d96
When timezone given and UTC, strip tz information. Test case of using…
evanjt Sep 6, 2023
a23b9e1
Add more flatten list cases, add condition to download.flatten_list()…
evanjt Sep 6, 2023
732b8ed
Replace props with info_dict
evanjt Sep 6, 2023
03d7578
Update gpm_api/tests/io/test_checks.py
ghiggi Sep 6, 2023
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
41 changes: 10 additions & 31 deletions gpm_api/io/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
Base directory where the GPM directory is located.
"""
# Check base_dir does not end with /
if base_dir[-1] == "/":
if base_dir[-1] == os.path.sep:

Check warning on line 35 in gpm_api/io/checks.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/io/checks.py#L35

Added line #L35 was not covered by tests
base_dir = base_dir[0:-1]
# Retrieve last folder name
dir_name = os.path.basename(base_dir)
Expand Down Expand Up @@ -157,15 +157,15 @@
if isinstance(time, np.ndarray):
if np.issubdtype(time.dtype, np.datetime64):
if time.size == 1:
time = time.astype("datetime64[s]").tolist()
time = time.astype("datetime64[us]").tolist()

Check warning on line 160 in gpm_api/io/checks.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/io/checks.py#L160

Added line #L160 was not covered by tests
evanjt marked this conversation as resolved.
Show resolved Hide resolved
else:
raise ValueError("Expecting a single timestep!")
else:
raise ValueError("The numpy array does not have a np.datetime64 dtype!")

# If np.datetime64, convert to datetime.datetime
# If np.datetime64, convert to datetime.datetime with microsecond precision
if isinstance(time, np.datetime64):
time = time.astype("datetime64[s]").tolist()
time = time.astype("datetime64[us]").tolist()

Check warning on line 168 in gpm_api/io/checks.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/io/checks.py#L168

Added line #L168 was not covered by tests
evanjt marked this conversation as resolved.
Show resolved Hide resolved
# If datetime.date, convert to datetime.datetime
if not isinstance(time, (datetime.datetime, str)):
time = datetime.datetime(time.year, time.month, time.day, 0, 0, 0)
Expand All @@ -178,11 +178,12 @@


def check_date(date):
if not isinstance(date, (datetime.date, datetime.datetime)):
raise ValueError("date must be a datetime object")
if isinstance(date, datetime.datetime):
date = date.date()
return date
if date is None:
raise ValueError("date cannot be None")

Check warning on line 182 in gpm_api/io/checks.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/io/checks.py#L181-L182

Added lines #L181 - L182 were not covered by tests

# Use check_time to convert to datetime.datetime
datetime_obj = check_time(date)
return datetime_obj.date()

Check warning on line 186 in gpm_api/io/checks.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/io/checks.py#L185-L186

Added lines #L185 - L186 were not covered by tests


def check_start_end_time(start_time, end_time):
Expand Down Expand Up @@ -225,25 +226,3 @@

# -------------------------------------------------------------------------.
return scan_mode


def check_bbox(bbox):
"""
Check correctness of bounding box.
bbox format: [lon_0, lon_1, lat_0, lat_1]
bbox should be provided with longitude between -180 and 180, and latitude
between -90 and 90.
"""
if bbox is None:
return bbox
# If bbox provided
if not (isinstance(bbox, list) and len(bbox) == 4):
raise ValueError("Provide valid bbox [lon_0, lon_1, lat_0, lat_1]")
if bbox[2] > 90 or bbox[2] < -90 or bbox[3] > 90 or bbox[3] < -90:
raise ValueError("Latitude is defined between -90 and 90")
# Try to be sure that longitude is specified between -180 and 180
if bbox[0] > 180 or bbox[1] > 180:
print("bbox should be provided with longitude between -180 and 180")
bbox[0] = bbox[0] - 180
bbox[1] = bbox[1] - 180
return bbox
2 changes: 0 additions & 2 deletions gpm_api/io/directories.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ def get_disk_dir_pattern(product, product_type, version):
GPM product name. See: gpm_api.available_products()
product_type : str, optional
GPM product type. Either 'RS' (Research) or 'NRT' (Near-Real-Time).
date : datetime.date
Single date for which to retrieve the data.
version : int, optional
GPM version of the data to retrieve if product_type = 'RS'.

Expand Down
3 changes: 1 addition & 2 deletions gpm_api/io/download.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
# -------------------------------------------------------------------------.
# Replace ftps with ftp to make curl work !!!
# - curl expects ftp:// and not ftps://
server_path = server_path.replace("ftps", "ftp", 1)
server_path = server_path.replace("ftps://", "ftp://", 1)

Check warning on line 64 in gpm_api/io/download.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/io/download.py#L64

Added line #L64 was not covered by tests
ghiggi marked this conversation as resolved.
Show resolved Hide resolved
# -------------------------------------------------------------------------.
## Define command to run
# Base command: curl -4 --ftp-ssl --user [user name]:[password] -n [url]
Expand Down Expand Up @@ -247,7 +247,6 @@
progress_bar=True,
verbose=False,
):

if transfer_tool == "curl":
list_cmd = [
curl_cmd(src_path, dst_path, username, username)
Expand Down
Empty file added gpm_api/tests/__init__.py
Empty file.
137 changes: 137 additions & 0 deletions gpm_api/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import pytest
import datetime
from typing import Any, List, Dict
from gpm_api.io.products import get_info_dict, available_products

Check warning on line 4 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L1-L4

Added lines #L1 - L4 were not covered by tests


@pytest.fixture
def product_types() -> List[str]:

Check warning on line 8 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L7-L8

Added lines #L7 - L8 were not covered by tests
"""Return a list of all product types from the info dict"""
product_types = []
for product, props in get_info_dict().items():
product_types += props["product_types"]

Check warning on line 12 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L10-L12

Added lines #L10 - L12 were not covered by tests

product_types = list(set(product_types)) # Dedup list

Check warning on line 14 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L14

Added line #L14 was not covered by tests

return product_types

Check warning on line 16 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L16

Added line #L16 was not covered by tests


@pytest.fixture
def product_categories() -> List[str]:

Check warning on line 20 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L19-L20

Added lines #L19 - L20 were not covered by tests
"""Return a list of product categories from the info dict"""

return list(set([props["product_category"] for props in get_info_dict().values()]))

Check warning on line 23 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L23

Added line #L23 was not covered by tests


@pytest.fixture
def product_levels() -> List[str]:

Check warning on line 27 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L26-L27

Added lines #L26 - L27 were not covered by tests
"""Return a list of product levels from the info dict"""

# Available in gpm_api.io.checks.check_product_level()
return ["1A", "1B", "1C", "2A", "2B"]

Check warning on line 31 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L31

Added line #L31 was not covered by tests
ghiggi marked this conversation as resolved.
Show resolved Hide resolved


@pytest.fixture
def versions() -> List[int]:

Check warning on line 35 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L34-L35

Added lines #L34 - L35 were not covered by tests
"""Return a list of versions"""

# Available in gpm_api.io.checks.check_version()
return [4, 5, 6, 7]

Check warning on line 39 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L39

Added line #L39 was not covered by tests
ghiggi marked this conversation as resolved.
Show resolved Hide resolved


@pytest.fixture
def products() -> List[str]:

Check warning on line 43 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L42-L43

Added lines #L42 - L43 were not covered by tests
"""Return a list of all products regardless of type"""

return available_products()

Check warning on line 46 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L46

Added line #L46 was not covered by tests


@pytest.fixture
def username() -> str:

Check warning on line 50 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L49-L50

Added lines #L49 - L50 were not covered by tests
ghiggi marked this conversation as resolved.
Show resolved Hide resolved
"""Return a username

GPM uses an email address as username
"""

return "[email protected]"

Check warning on line 56 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L56

Added line #L56 was not covered by tests


@pytest.fixture
def password() -> str:

Check warning on line 60 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L59-L60

Added lines #L59 - L60 were not covered by tests
"""Return a password

GPM password is the username
"""

return "[email protected]"

Check warning on line 66 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L66

Added line #L66 was not covered by tests


@pytest.fixture
def server_paths() -> Dict[str, Dict[str, Any]]:

Check warning on line 70 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L69-L70

Added lines #L69 - L70 were not covered by tests
"""Return a list of probable GPM server paths"""

# Not validated to be real paths but follow the structure
ghiggi marked this conversation as resolved.
Show resolved Hide resolved
return {

Check warning on line 74 in gpm_api/tests/conftest.py

View check run for this annotation

Codecov / codecov/patch

gpm_api/tests/conftest.py#L74

Added line #L74 was not covered by tests
"ftps://arthurhouftps.pps.eosdis.nasa.gov/gpmdata/2020/07/05/radar/2A.GPM.DPR.V9-20211125.20200705-S170044-E183317.036092.V07A.HDF5": {
"year": 2020,
"month": 7,
"day": 5,
"product_category": "radar",
"product_type": "RS",
"start_time": datetime.datetime(2020, 7, 5, 17, 0, 44),
"end_time": datetime.datetime(2020, 7, 5, 18, 33, 17),
"version": 7,
},
"ftps://arthurhouftps.pps.eosdis.nasa.gov/gpmdata/2020/07/05/radar/2A.GPM.DPR.V9-20211125.20200705-S183318-E200550.036093.V07A.HDF5": {
ghiggi marked this conversation as resolved.
Show resolved Hide resolved
"year": 2020,
"month": 7,
"day": 5,
"product_category": "radar",
"product_type": "RS",
"start_time": datetime.datetime(2020, 7, 5, 18, 33, 18),
"end_time": datetime.datetime(2020, 7, 5, 20, 5, 50),
"version": 7,
},
"ftps://arthurhouftps.pps.eosdis.nasa.gov/gpmdata/2020/07/05/radar/2A.GPM.DPR.V9-20211125.20200705-S200551-E213823.036094.V07A.HDF5": {
"year": 2020,
"month": 7,
"day": 5,
"product_category": "radar",
"product_type": "RS",
"start_time": datetime.datetime(2020, 7, 5, 20, 5, 51),
"end_time": datetime.datetime(2020, 7, 5, 21, 38, 23),
"version": 7,
},
# Include non-ftps folders
"ftp://arthurhouftps.pps.eosdis.nasa.gov/gpmdata/2020/07/05/radar/2A.GPM.DPR.V9-20211125.20200705-S213824-E231056.036095.V07A.HDF5": {
"year": 2020,
"month": 7,
"day": 5,
"product_category": "radar",
"product_type": "RS",
"start_time": datetime.datetime(2020, 7, 5, 21, 38, 24),
"end_time": datetime.datetime(2020, 7, 5, 23, 10, 56),
"version": 7,
},
"ftp://arthurhouftps.pps.eosdis.nasa.gov/gpmdata/2020/07/05/radar/2A.GPM.DPR.V9-20211125.20200705-S231057-E004329.036096.V07A.HDF5": {
"year": 2020,
"month": 7,
"day": 5,
"product_category": "radar",
"product_type": "RS",
"start_time": datetime.datetime(2020, 7, 5, 23, 10, 57),
"end_time": datetime.datetime(2020, 7, 6, 0, 43, 29),
"version": 7,
},
"ftp://arthurhouftps.pps.eosdis.nasa.gov/gpmdata/2020/07/05/radar/2A.GPM.DPR.V9-20211125.20200705-S004330-E021602.036097.V07A.HDF5": {
"year": 2020,
"month": 7,
"day": 5,
"product_category": "radar",
"product_type": "RS",
"start_time": datetime.datetime(2020, 7, 5, 0, 43, 30),
"end_time": datetime.datetime(2020, 7, 5, 2, 16, 2),
"version": 7,
},
# TODO: Add more products with varying attributes ...
ghiggi marked this conversation as resolved.
Show resolved Hide resolved
}
Loading