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
1 change: 0 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@
"_build",
"jupyter_execute",
"**.ipynb_checkpoints",
"user_guide/examples_v3",
".jupyter_cache",
]

Expand Down
3 changes: 3 additions & 0 deletions pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ pytest-cov = "*"
pytest-reportlog = "*"
pytest-timeout = "*"

[feature.test.pypi-dependencies]
re-assert = "*"
Comment on lines +86 to +87

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes it very easy to test strings against regexes in Pytest.

https://github.com/asottile/re-assert

with

 def test_field_repr(fieldset):
-    Matches(r"Field\(name=.*, model=.*\)").assert_matches(repr(fieldset.U))
+    Matches(r"Field\(field_name=.*, model=.*\)").assert_matches(repr(fieldset.U))
 
 
 def test_vectorfield_repr(fieldset):

it gives failure of

E       AssertionError:  regex failed to match at:
E       
E       > Field(name='U', model=<parcels._core.model.StructuredModelData object at 0x333847110>)
E               ^

.pixi/envs/default/lib/python3.14/site-packages/re_assert.py:63: AssertionError

As opposed to a generic uninformative "regex failed to match" error that we'd get from the re library directly


[feature.test.tasks]
tests = { cmd = "pytest", description = "Run the test suite." }
tests-flaky = { cmd = "pytest -m 'flaky' --run-flaky-tests", description = "Run only flaky tests." }
Expand Down
8 changes: 1 addition & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ dependencies = [
"cftime >=1.6.3",
"numpy >=2.1.0",
"dask >=2024.5.1",
"netCDF4 >=1.7.2", # TODO: should we use h5netcdf here instead of netCDF4?
"netCDF4 >=1.7.2",
"zarr >=3",
"tqdm >=4.50.0",
"xarray >=2024.5.0",
Expand Down Expand Up @@ -53,7 +53,6 @@ local_scheme = "no-local-version"
[tool.pytest.ini_options]
addopts = ["--strict-config", "--strict-markers"]
xfail_strict = true
# testpaths = ["tests", "docs/examples"] # TODO v4: Re-enable once examples are back/fixed
testpaths = ["tests"]
python_files = ["test_*.py", "example_*.py", "*tutorial*"]
minversion = "7"
Expand Down Expand Up @@ -101,11 +100,6 @@ select = [
"NPY201", # numpy 2 deprecations
]

exclude = [
"tests-v3/**",
'docs/user_guide/examples_v3/**',
] # TODO v4: Remove once folders are gone

ignore = [
# # Rules intentionally excluded
# line too long (82 > 79 characters)
Expand Down
2 changes: 1 addition & 1 deletion src/parcels/_core/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def time_interval(self): # TODO PR: Remove in favour of referencing model time_
return self.model.time_interval

def __repr__(self):
return f"Field(name={self.name}, model={self.model})"
return f"Field(name={self.name!r}, model={self.model})"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensures quotes. i.e., Field(name='U', ... instead of Field(name=U


@property
def interp_method(self):
Expand Down
2 changes: 1 addition & 1 deletion src/parcels/_datasets/structured/generated.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def radial_rotation_dataset(xdim=200, ydim=200): # Define 2D flat, square field
)


def moving_eddy_dataset(xdim=2, ydim=2): # TODO check if this also works with xdim=1, ydim=1
def moving_eddy_dataset(xdim=2, ydim=2):
Comment thread
erikvansebille marked this conversation as resolved.
"""Create a dataset with an eddy moving in time. Note that there is no spatial variation in the flow."""
f, u_0, u_g = 1.0e-4, 0.3, 0.04 # Some constants

Expand Down
4 changes: 1 addition & 3 deletions src/parcels/_repr_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ def fieldset_repr(fieldset: FieldSet) -> str:
return textwrap.dedent(out).strip()


# TODO add land_value here after HG #2451 is merged
Comment thread
erikvansebille marked this conversation as resolved.
def field_repr(field: Field, level: int = 0) -> str:
"""Return a pretty repr for Field"""
with xr.set_options(display_expand_data=False):
Expand Down Expand Up @@ -138,8 +137,7 @@ def particlefile_repr(pfile: Any) -> str:
out = f"""<{type(pfile).__name__}>
path : {pfile.path}
outputdt : {pfile.outputdt!r}
metadata :
{_format_list_items_multiline(pfile.metadata, level=2, with_brackets=False)}
metadata : {_format_list_items_multiline(pfile.metadata, level=2, with_brackets=False)}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

formatting fix

"""
return textwrap.dedent(out).strip()

Expand Down
2 changes: 1 addition & 1 deletion src/parcels/_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def _validate_against_pure_literal(value, typing_literal):

Can't be used with ``Literal[...] | None`` etc. as its not a pure literal.
"""
# TODO remove once https://github.com/pydata/xarray/issues/11209 is resolved - Xarray objects don't work normally in `in` statements
# Xarray objects don't work normally in `in` statements - see https://github.com/pydata/xarray/issues/11209 (this is unlikely to be resolved anytime soon)
if _is_xarray_object(value):
raise ValueError(f"Invalid input type {type(value)}")

Expand Down
115 changes: 0 additions & 115 deletions tests-v3/test_reprs.py

This file was deleted.

9 changes: 9 additions & 0 deletions tests/test_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import numpy as np
import pytest
from re_assert import Matches

from parcels import Field, VectorField
from parcels._core.fieldset import FieldSet
Expand Down Expand Up @@ -39,6 +40,14 @@ def test_field_init_param_types():
Field(name="while", model=model)


def test_field_repr(fieldset):
Matches(r"Field\(name=.*, model=.*\)").assert_matches(repr(fieldset.U))


def test_vectorfield_repr(fieldset):
Matches(r"\<.*VectorField object at.*\>").assert_matches(repr(fieldset.UV))


# TODO: Move to test_model.py ?
def test_field_init_fail_on_float_time_dim():
"""Test that accessing time_interval fails when dataset has float time dimension.
Expand Down
5 changes: 5 additions & 0 deletions tests/test_fieldset.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pandas as pd
import pytest
import xarray as xr
from re_assert import Matches

import parcels.tutorial
import tests
Expand Down Expand Up @@ -40,6 +41,10 @@ def test_fieldset_init_wrong_types():
FieldSet([1.0, 2.0, 3.0])


def test_fieldset_repr(fieldset):
Matches(r"\<.*FieldSet object at.*\>").assert_matches(repr(fieldset))


def test_fieldset_add_context(fieldset):
fieldset.add_context("test_context", 1.0)
assert fieldset.test_context == 1.0
Expand Down
15 changes: 14 additions & 1 deletion tests/test_particlefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,21 @@
import pyarrow.parquet as pq
import pytest
import xarray as xr
from re_assert import Matches

import parcels.tutorial
from parcels import (
Field,
FieldSet,
Particle,
ParticleFile,
ParticleSet,
ParticleSetWarning,
StatusCode,
Variable,
convert,
)
from parcels._core.particle import Particle, get_default_particle
from parcels._core.particle import get_default_particle
from parcels._core.particlefile import get_schema
from parcels._core.utils.time import TimeInterval, timedelta_to_float
from parcels._datasets.structured.generated import peninsula_dataset
Expand All @@ -30,6 +32,17 @@
from tests.common_kernels import DoNothing


def test_particlefile_repr(tmp_parquet):
pfile_repr = repr(ParticleFile(tmp_parquet, outputdt=np.timedelta64(1, "s")))
match = Matches(
r"""\<ParticleFile\>
path : .*
outputdt : 1.0
metadata : .*""",
)
match.assert_matches(pfile_repr)


def test_metadata(fieldset, tmp_parquet):
pset = ParticleSet(fieldset, pclass=Particle, x=0, y=0)

Expand Down
5 changes: 5 additions & 0 deletions tests/test_particleset.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import numpy as np
import pytest
import xarray as xr
from re_assert import Matches

from parcels import (
FieldSet,
Expand Down Expand Up @@ -35,6 +36,10 @@ def test_create_empty_pset(fieldset):
assert pset.size == 0


def test_particleset_repr(fieldset):
Matches(r"\<.*ParticleSet object at.*\>").assert_matches(repr(ParticleSet(fieldset, pclass=Particle)))


@pytest.mark.parametrize("offset", [0, 1, 200])
def test_pset_with_pids(fieldset, offset, npart=100):
lon = np.linspace(0, 1, npart)
Expand Down
5 changes: 5 additions & 0 deletions tests/test_xgrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import pytest
import xarray as xr
from numpy.testing import assert_allclose
from re_assert import Matches

from parcels import FieldSet
from parcels._core.index_search import (
Expand Down Expand Up @@ -56,6 +57,10 @@ def test_grid_init_param_types(ds):
XGrid.from_dataset(ds, mesh="invalid")


def test_xgrid_repr(fieldset):
Matches(r"\<.*XGrid object at.*\>").assert_matches(repr(fieldset.U.grid))


@pytest.mark.parametrize("ds, attr, expected", test_cases)
def test_xgrid_properties_ground_truth(ds, attr, expected):
grid = FieldSet.from_sgrid_conventions(ds, mesh="flat").data_g.grid
Expand Down