Skip to content

Commit 6b5bb9a

Browse files
authored
Merge pull request #99 from ocefpaf/coverage
implement coverage tests
2 parents 6285b4b + 04dc5db commit 6b5bb9a

11 files changed

Lines changed: 1414 additions & 229 deletions

File tree

.github/workflows/codecov.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Code coverage report
2+
3+
# no permissions by default
4+
permissions: {}
5+
6+
on:
7+
pull_request:
8+
push:
9+
10+
jobs:
11+
run:
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
16+
with:
17+
persist-credentials: false
18+
19+
- name: Setup pixi
20+
uses: prefix-dev/setup-pixi@82d477f15f3a381dbcc8adc1206ce643fe110fb7 # v0.9.3
21+
with:
22+
cache: true
23+
24+
- name: Run tests with coverage
25+
run: >
26+
pixi run --environment testcov test_cov

.pre-commit-config.yaml

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,14 @@ repos:
2727
- --ignore-words-list=astroid,fo
2828

2929
- repo: https://github.com/astral-sh/ruff-pre-commit
30-
rev: v0.14.10
30+
rev: v0.15.0
3131
hooks:
3232
- id: ruff
3333
args: ["--fix", "--show-fixes"]
3434
- id: ruff-format
3535

36-
- repo: https://github.com/tox-dev/pyproject-fmt
37-
rev: v2.11.1
38-
hooks:
39-
- id: pyproject-fmt
40-
4136
- repo: https://github.com/woodruffw/zizmor-pre-commit
42-
rev: v1.19.0
37+
rev: v1.22.0
4338
hooks:
4439
- id: zizmor
4540

pixi.lock

Lines changed: 1236 additions & 92 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ dependencies = [
3636
"cf-xarray",
3737
"cftime",
3838
"dask",
39-
# "dask[complete]", # getting errors from pixi with the "complete"
4039
"netcdf4",
4140
"numpy",
4241
"xarray>=2024.6",
@@ -51,7 +50,7 @@ optional-dependencies.dev = [
5150
"sphinx-rtd-theme",
5251
]
5352
optional-dependencies.examples = [ "fsspec", "h5netcdf", "matplotlib", "s3fs", "zarr<3" ]
54-
urls."Homepage" = "https://github.com/asascience-open/xarray-subset-grid"
53+
urls."Homepage" = "https://github.com/ioos/xarray-subset-grid/"
5554

5655
[tool.setuptools]
5756
packages = [ "xarray_subset_grid" ]
@@ -108,6 +107,7 @@ test311 = [ "dev", "py311" ]
108107
test312 = [ "dev", "py312" ]
109108
test313 = [ "dev", "py313" ]
110109
test314 = [ "dev", "py314" ]
110+
testcov = [ "dev", "py314" ]
111111

112112
[tool.pixi.system-requirements]
113113
macos = "11.0"
@@ -146,6 +146,7 @@ myst-nb = "*"
146146
lint = "ruff check tests xarray_subset_grid"
147147
test = "pytest tests/"
148148
test_all = "pytest --online tests/"
149+
test_cov = "pytest --cov=xarray_subset_grid tests"
149150

150151
[tool.pixi.feature.examples.dependencies]
151152
matplotlib = "*"

tests/conftest.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,20 @@ def pytest_collection_modifyitems(config, items):
3838
# if item.config.getoption("-E") not in envnames:
3939
# pytest.skip(f"test requires env in {envnames!r}")
4040

41-
EXAMPLE_DATA = Path(__file__).parent / 'example_data'
42-
43-
UGRID_FILES = [EXAMPLE_DATA / 'SFBOFS_subset1.nc',
44-
EXAMPLE_DATA / 'small_ugrid_zero_based.nc',
45-
EXAMPLE_DATA / 'tris_and_bounds.nc',
46-
]
47-
48-
SGRID_FILES = [EXAMPLE_DATA / 'arakawa_c_test_grid.nc',
49-
]
50-
51-
RGRID_FILES = [EXAMPLE_DATA / '2D-rectangular_grid_wind.nc',
52-
EXAMPLE_DATA / 'rectangular_grid_decreasing.nc',
53-
EXAMPLE_DATA / 'AMSEAS-subset.nc',
54-
]
41+
EXAMPLE_DATA = Path(__file__).parent / "example_data"
42+
43+
UGRID_FILES = [
44+
EXAMPLE_DATA / "SFBOFS_subset1.nc",
45+
EXAMPLE_DATA / "small_ugrid_zero_based.nc",
46+
EXAMPLE_DATA / "tris_and_bounds.nc",
47+
]
48+
49+
SGRID_FILES = [
50+
EXAMPLE_DATA / "arakawa_c_test_grid.nc",
51+
]
52+
53+
RGRID_FILES = [
54+
EXAMPLE_DATA / "2D-rectangular_grid_wind.nc",
55+
EXAMPLE_DATA / "rectangular_grid_decreasing.nc",
56+
EXAMPLE_DATA / "AMSEAS-subset.nc",
57+
]

tests/test_grids/test_regular_grid.py

Lines changed: 72 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
# It was created by the "OFS subsetter"
2626

27+
2728
@pytest.mark.parametrize("test_file", RGRID_FILES)
2829
def test_recognize(test_file):
2930
"""
@@ -77,8 +78,6 @@ def create_synthetic_rectangular_grid_dataset(decreasing=False):
7778
return ds
7879

7980

80-
81-
8281
def test_grid_vars():
8382
"""
8483
Check if the grid vars are defined properly
@@ -88,7 +87,7 @@ def test_grid_vars():
8887
grid_vars = ds.xsg.grid_vars
8988

9089
# ['mesh', 'nv', 'lon', 'lat', 'lonc', 'latc']
91-
assert grid_vars == {'lat', 'lon'}
90+
assert grid_vars == {"lat", "lon"}
9291

9392

9493
def test_data_vars():
@@ -106,27 +105,28 @@ def test_data_vars():
106105
# the extra "time" variables are not using the grid
107106
# so they should not be listed as data_vars
108107
assert data_vars == {
109-
'water_w',
110-
'salinity',
111-
'surf_roughness',
112-
'surf_temp_flux',
113-
'water_v',
108+
"water_w",
109+
"salinity",
110+
"surf_roughness",
111+
"surf_temp_flux",
112+
"water_v",
114113
# 'time_offset',
115-
'water_temp',
116-
'water_baro_v',
117-
'surf_atm_press',
118-
'surf_el',
119-
'surf_salt_flux',
120-
'water_u',
121-
'surf_wnd_stress_gridy',
122-
'water_baro_u',
123-
'watdep',
124-
'surf_solar_flux',
114+
"water_temp",
115+
"water_baro_v",
116+
"surf_atm_press",
117+
"surf_el",
118+
"surf_salt_flux",
119+
"water_u",
120+
"surf_wnd_stress_gridy",
121+
"water_baro_u",
122+
"watdep",
123+
"surf_solar_flux",
125124
# 'time1_run',
126-
'surf_wnd_stress_gridx',
125+
"surf_wnd_stress_gridx",
127126
# 'time1_offset'
128127
}
129128

129+
130130
# might not be needed if tested elsewhere.
131131
def test_data_vars2():
132132
"""
@@ -141,7 +141,7 @@ def test_data_vars2():
141141
data_vars = ds.xsg.data_vars
142142
print(f"data_vars: {data_vars}")
143143

144-
assert data_vars == {'salt', 'temp'}
144+
assert data_vars == {"salt", "temp"}
145145

146146

147147
def test_extra_vars():
@@ -154,42 +154,43 @@ def test_extra_vars():
154154

155155
# the extra "time" variables are not using the grid
156156
# so they should be listed as extra_vars
157-
assert extra_vars == {
158-
'time_offset',
159-
'time1_run',
160-
'time1_offset'
161-
}
157+
assert extra_vars == {"time_offset", "time1_run", "time1_offset"}
158+
162159

163160
def test_subset_to_bb():
164161
"""
165162
Not a complete test by any means, but the basics are there.
166163
167-
NOTE: it doesn't test if the variables got subset corectly ...
164+
NOTE: it doesn't test if the variables got subset correctly ...
168165
169166
"""
170167
ds = xr.open_dataset(EXAMPLE_DATA / "2D-rectangular_grid_wind.nc")
171168

172-
print("initial bounds:", ds['lon'].data.min(),
173-
ds['lat'].data.min(),
174-
ds['lon'].data.max(),
175-
ds['lat'].data.max(),
176-
)
169+
print(
170+
"initial bounds:",
171+
ds["lon"].data.min(),
172+
ds["lat"].data.min(),
173+
ds["lon"].data.max(),
174+
ds["lat"].data.max(),
175+
)
177176

178177
bbox = (-0.5, 0, 0.5, 0.5)
179178

180179
ds2 = ds.xsg.subset_bbox(bbox)
181180

182-
assert ds2['lat'].size == 15
183-
assert ds2['lon'].size == 29
181+
assert ds2["lat"].size == 15
182+
assert ds2["lon"].size == 29
184183

185-
new_bounds = (ds2['lon'].data.min(),
186-
ds2['lat'].data.min(),
187-
ds2['lon'].data.max(),
188-
ds2['lat'].data.max(),
189-
)
184+
new_bounds = (
185+
ds2["lon"].data.min(),
186+
ds2["lat"].data.min(),
187+
ds2["lon"].data.max(),
188+
ds2["lat"].data.max(),
189+
)
190190
print("new bounds:", new_bounds)
191191
assert new_bounds == bbox
192192

193+
193194
def test_decreasing_latitude():
194195
"""
195196
Some datasets have the latitude or longitude decreasing: 10, 9, 8 etc.
@@ -200,27 +201,31 @@ def test_decreasing_latitude():
200201
"""
201202
ds = xr.open_dataset(EXAMPLE_DATA / "rectangular_grid_decreasing.nc")
202203

203-
print("initial bounds:", ds['lon'].data.min(),
204-
ds['lat'].data.min(),
205-
ds['lon'].data.max(),
206-
ds['lat'].data.max(),
207-
)
204+
print(
205+
"initial bounds:",
206+
ds["lon"].data.min(),
207+
ds["lat"].data.min(),
208+
ds["lon"].data.max(),
209+
ds["lat"].data.max(),
210+
)
208211

209212
bbox = (-0.5, 0, 0.5, 0.5)
210213

211214
ds2 = ds.xsg.subset_bbox(bbox)
212215

213-
assert ds2['lat'].size == 15
214-
assert ds2['lon'].size == 29
216+
assert ds2["lat"].size == 15
217+
assert ds2["lon"].size == 29
215218

216-
new_bounds = (ds2['lon'].data.min(),
217-
ds2['lat'].data.min(),
218-
ds2['lon'].data.max(),
219-
ds2['lat'].data.max(),
220-
)
219+
new_bounds = (
220+
ds2["lon"].data.min(),
221+
ds2["lat"].data.min(),
222+
ds2["lon"].data.max(),
223+
ds2["lat"].data.max(),
224+
)
221225
print("new bounds:", new_bounds)
222226
assert new_bounds == bbox
223227

228+
224229
def test_decreasing_coords():
225230
"""
226231
Redundant with above, but already written ...
@@ -239,20 +244,23 @@ def test_decreasing_coords():
239244
assert subset.sizes["lat"] > 0
240245
assert subset.sizes["lon"] > 0
241246

247+
242248
def test_subset_polygon():
243249
"""
244250
Not a complete test by any means, but the basics are there.
245251
246-
NOTE: it doesn't test if the variables got subset corectly ...
252+
NOTE: it doesn't test if the variables got subset correctly ...
247253
248254
"""
249255
ds = xr.open_dataset(EXAMPLE_DATA / "2D-rectangular_grid_wind.nc")
250256

251-
print("initial bounds:", ds['lon'].data.min(),
252-
ds['lat'].data.min(),
253-
ds['lon'].data.max(),
254-
ds['lat'].data.max(),
255-
)
257+
print(
258+
"initial bounds:",
259+
ds["lon"].data.min(),
260+
ds["lat"].data.min(),
261+
ds["lon"].data.max(),
262+
ds["lat"].data.max(),
263+
)
256264

257265
poly = [(-0.5, 0.0), (0.0, 0.5), (0.5, 0.5), (0.5, 0.0), (0, 0.0)]
258266
# this poly has this bounding box:
@@ -261,19 +269,19 @@ def test_subset_polygon():
261269

262270
ds2 = ds.xsg.subset_polygon(poly)
263271

264-
assert ds2['lat'].size == 15
265-
assert ds2['lon'].size == 29
272+
assert ds2["lat"].size == 15
273+
assert ds2["lon"].size == 29
266274

267-
new_bounds = (ds2['lon'].data.min(),
268-
ds2['lat'].data.min(),
269-
ds2['lon'].data.max(),
270-
ds2['lat'].data.max(),
271-
)
275+
new_bounds = (
276+
ds2["lon"].data.min(),
277+
ds2["lat"].data.min(),
278+
ds2["lon"].data.max(),
279+
ds2["lat"].data.max(),
280+
)
272281
print("new bounds:", new_bounds)
273282
assert new_bounds == (-0.5, 0, 0.5, 0.5)
274283

275284

276-
277285
# def test_vertical_levels():
278286
# ds = xr.open_dataset(EXAMPLE_DATA / "SFBOFS_subset1.nc")
279287
# ds = ugrid.assign_ugrid_topology(ds, **grid_topology)

tests/test_grids/test_ugrid.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
EXAMPLE_DATA = Path(__file__).parent.parent / "example_data"
2121

22+
2223
@pytest.mark.parametrize("test_file", UGRID_FILES[:3])
2324
def test_recognize(test_file):
2425
"""
@@ -31,14 +32,10 @@ def test_recognize(test_file):
3132
except KeyError: # no mesh variable
3233
# Hacky way to deal with non-conforming examples
3334
# This should be in a config somewhere, or ??
34-
if 'tris' in ds:
35-
grid_top = {'face_node_connectivity': 'tris',
36-
'node_coordinates': ('lon', 'lat')
37-
}
38-
elif 'nv' in ds:
39-
grid_top = {'face_node_connectivity': 'nv',
40-
'node_coordinates': ('lon', 'lat')
41-
}
35+
if "tris" in ds:
36+
grid_top = {"face_node_connectivity": "tris", "node_coordinates": ("lon", "lat")}
37+
elif "nv" in ds:
38+
grid_top = {"face_node_connectivity": "nv", "node_coordinates": ("lon", "lat")}
4239
ds = ugrid.assign_ugrid_topology(ds, **grid_top)
4340

4441
assert UGrid.recognize(ds)

0 commit comments

Comments
 (0)