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
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,6 @@ known-first-party = ["parcels"]

[tool.ty.src]
include = ["./src/"]
exclude = [
"./src/parcels/interpolators/", # ignore for now
]
4 changes: 2 additions & 2 deletions src/parcels/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
KMeans: Any | None = None

try:
from mpi4py import MPI # type: ignore[no-redef]
from mpi4py import MPI # type: ignore[import-untyped,no-redef]
except ModuleNotFoundError:
pass

# KMeans is used in MPI. sklearn not installed by default
try:
from sklearn.cluster import KMeans # type: ignore[no-redef]
from sklearn.cluster import KMeans
except ModuleNotFoundError:
pass

Expand Down
6 changes: 3 additions & 3 deletions src/parcels/_core/field.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import warnings
from collections.abc import Callable
from collections.abc import Callable, Sequence
from datetime import datetime

import numpy as np
Expand Down Expand Up @@ -144,21 +144,21 @@
@property
def xdim(self):
if type(self.data) is xr.DataArray:
return self.grid.xdim

Check failure on line 147 in src/parcels/_core/field.py

View workflow job for this annotation

GitHub Actions / TypeChecking: pixi run typing

ty (unresolved-attribute)

src/parcels/_core/field.py:147:20: unresolved-attribute: Attribute `xdim` is not defined on `UxGrid` in union `Unknown | UxGrid | XGrid` info: rule `unresolved-attribute` is enabled by default
else:
raise NotImplementedError("xdim not implemented for unstructured grids")

@property
def ydim(self):
if type(self.data) is xr.DataArray:
return self.grid.ydim

Check failure on line 154 in src/parcels/_core/field.py

View workflow job for this annotation

GitHub Actions / TypeChecking: pixi run typing

ty (unresolved-attribute)

src/parcels/_core/field.py:154:20: unresolved-attribute: Attribute `ydim` is not defined on `UxGrid` in union `Unknown | UxGrid | XGrid` info: rule `unresolved-attribute` is enabled by default
else:
raise NotImplementedError("ydim not implemented for unstructured grids")

@property
def zdim(self):
if type(self.data) is xr.DataArray:
return self.grid.zdim

Check failure on line 161 in src/parcels/_core/field.py

View workflow job for this annotation

GitHub Actions / TypeChecking: pixi run typing

ty (unresolved-attribute)

src/parcels/_core/field.py:161:20: unresolved-attribute: Attribute `zdim` is not defined on `UxGrid` in union `Unknown | UxGrid | XGrid` info: rule `unresolved-attribute` is enabled by default
else:
if "nz1" in self.data.dims:
return self.data.sizes["nz1"]
Expand Down Expand Up @@ -428,7 +428,7 @@
)


def _assert_compatible_combination(data: xr.DataArray | ux.UxDataArray, grid: ux.Grid | XGrid):
def _assert_compatible_combination(data: xr.DataArray | ux.UxDataArray, grid: UxGrid | XGrid):
if isinstance(data, ux.UxDataArray):
if not isinstance(grid, UxGrid):
raise ValueError(
Expand All @@ -448,7 +448,7 @@
return TimeInterval(data.time.values[0], data.time.values[-1])


def _assert_same_time_interval(fields: list[Field]) -> None:
def _assert_same_time_interval(fields: Sequence[Field]) -> None:
if len(fields) == 0:
return

Expand Down
6 changes: 3 additions & 3 deletions src/parcels/_core/fieldset.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@
f"Dataset missing one of the required dimensions 'time', 'zf', or 'zc' for uxDataset. Found dimensions {ds_dims}"
)

grid = UxGrid(ds.uxgrid, z=ds.coords["zf"], mesh=mesh)

Check failure on line 210 in src/parcels/_core/fieldset.py

View workflow job for this annotation

GitHub Actions / TypeChecking: pixi run typing

ty (invalid-argument-type)

src/parcels/_core/fieldset.py:210:34: invalid-argument-type: Argument to bound method `__init__` is incorrect: Expected `UxDataArray`, found `DataArray` src/parcels/_core/uxgrid.py:21:9: info: Method defined here src/parcels/_core/uxgrid.py:21:44: Parameter declared here info: rule `invalid-argument-type` is enabled by default
ds = _discover_ux_U_and_V(ds)

fields = {}
Expand All @@ -223,7 +223,7 @@
)

for varname in set(ds.data_vars) - set(fields.keys()):
fields[varname] = Field(varname, ds[varname], grid, _select_uxinterpolator(ds[varname]))
fields[varname] = Field(str(varname), ds[varname], grid, _select_uxinterpolator(ds[varname]))

return cls(list(fields.values()))

Expand Down Expand Up @@ -319,7 +319,7 @@
)

for varname in set(ds.data_vars) - set(fields.keys()) - skip_vars:
fields[varname] = Field(varname, ds[varname], grid, XLinear)
fields[varname] = Field(str(varname), ds[varname], grid, XLinear)

return cls(list(fields.values()))

Expand Down Expand Up @@ -353,8 +353,8 @@
return msg


def _format_calendar_error_message(field: Field, reference_datetime: TimeLike) -> str:
def _format_calendar_error_message(field: Field | VectorField, reference_datetime: TimeLike) -> str:
return f"Expected field {field.name!r} to have calendar compatible with datetime object {_datetime_to_msg(reference_datetime)}. Got field with calendar {_datetime_to_msg(field.time_interval.left)}. Have you considered using xarray to update the time dimension of the dataset to have a compatible calendar?"

Check failure on line 357 in src/parcels/_core/fieldset.py

View workflow job for this annotation

GitHub Actions / TypeChecking: pixi run typing

ty (unresolved-attribute)

src/parcels/_core/fieldset.py:357:175: unresolved-attribute: Attribute `left` is not defined on `None` in union `Unknown | TimeInterval | None` info: rule `unresolved-attribute` is enabled by default


_COPERNICUS_MARINE_AXIS_VARNAMES = {
Expand Down Expand Up @@ -401,7 +401,7 @@
if "W" not in ds:
for common_W in common_ux_W:
if common_W in ds:
ds = _ds_rename_using_standard_names(ds, {common_W: "W"})

Check failure on line 404 in src/parcels/_core/fieldset.py

View workflow job for this annotation

GitHub Actions / TypeChecking: pixi run typing

ty (invalid-assignment)

src/parcels/_core/fieldset.py:404:22: invalid-assignment: Object of type `Dataset` is not assignable to `UxDataset` src/parcels/_core/fieldset.py:404:17: Declared type `UxDataset` info: rule `invalid-assignment` is enabled by default
break

if "U" in ds and "V" in ds:
Expand All @@ -420,7 +420,7 @@
"Please rename the appropriate variables in your dataset to have both 'U' and 'V' for Parcels simulation."
)
else:
ds = _ds_rename_using_standard_names(ds, {common_U: "U", common_V: "V"})

Check failure on line 423 in src/parcels/_core/fieldset.py

View workflow job for this annotation

GitHub Actions / TypeChecking: pixi run typing

ty (invalid-assignment)

src/parcels/_core/fieldset.py:423:22: invalid-assignment: Object of type `Dataset` is not assignable to `UxDataset` src/parcels/_core/fieldset.py:423:17: Declared type `UxDataset` info: rule `invalid-assignment` is enabled by default
break

else:
Expand Down Expand Up @@ -481,7 +481,7 @@

sgrid_metadata = sgrid.parse_grid_attrs(grid_da.attrs)

fpoint_x, fpoint_y = sgrid_metadata.node_coordinates

Check failure on line 484 in src/parcels/_core/fieldset.py

View workflow job for this annotation

GitHub Actions / TypeChecking: pixi run typing

ty (not-iterable)

src/parcels/_core/fieldset.py:484:26: not-iterable: Object of type `None` is not iterable info: It doesn't have an `__iter__` method or a `__getitem__` method info: rule `not-iterable` is enabled by default

Check failure on line 484 in src/parcels/_core/fieldset.py

View workflow job for this annotation

GitHub Actions / TypeChecking: pixi run typing

ty (invalid-assignment)

src/parcels/_core/fieldset.py:484:5: invalid-assignment: Too many values to unpack: Expected 2 src/parcels/_core/fieldset.py:484:26: Got 3 info: rule `invalid-assignment` is enabled by default

if _is_coordinate_in_degrees(ds_sgrid[fpoint_x]) ^ _is_coordinate_in_degrees(ds_sgrid[fpoint_x]):
msg = (
Expand Down
4 changes: 2 additions & 2 deletions src/parcels/_core/index_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

if TYPE_CHECKING:
from parcels._core.field import Field
from parcels.xgrid import XGrid
from parcels._core.xgrid import XGrid


GRID_SEARCH_ERROR = -3
Expand All @@ -19,7 +19,7 @@


def _search_1d_array(
arr: np.array,
arr: np.ndarray,
x: float,
) -> tuple[int, int]:
"""
Expand All @@ -44,7 +44,7 @@
"""
# TODO v4: We probably rework this to deal with 0D arrays before this point (as we already know field dimensionality)
if len(arr) < 2:
return np.zeros(shape=x.shape, dtype=np.int32), np.zeros_like(x)

Check failure on line 47 in src/parcels/_core/index_search.py

View workflow job for this annotation

GitHub Actions / TypeChecking: pixi run typing

ty (invalid-return-type)

src/parcels/_core/index_search.py:47:16: invalid-return-type: Return type does not match returned value: expected `tuple[int, int]`, found `tuple[Unknown, ndarray[tuple[Any, ...], dtype[Any]]]` src/parcels/_core/index_search.py:24:6: Expected `tuple[int, int]` because of return type info: rule `invalid-return-type` is enabled by default
index = np.clip(np.searchsorted(arr, x, side="right") - 1, 0, len(arr) - 2)
# Use broadcasting to avoid repeated array access
arr_index = arr[index]
Expand Down
8 changes: 4 additions & 4 deletions src/parcels/_core/particle.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import operator
from typing import Literal
from typing import Any, Literal

import numpy as np

Expand Down Expand Up @@ -37,7 +37,7 @@ class Variable:
def __init__(
self,
name,
dtype: np.dtype = np.float32,
dtype: np.dtype[Any] | type[np.generic] = np.float32,
initial=0,
to_write: bool | Literal["once"] = True,
attrs: dict | None = None,
Expand Down Expand Up @@ -122,7 +122,7 @@ def _assert_no_duplicate_variable_names(*, existing_vars: list[Variable], new_va
raise ValueError(f"Variable name already exists: {var.name}")


def get_default_particle(spatial_dtype: np.float32 | np.float64) -> ParticleClass:
def get_default_particle(spatial_dtype: type[np.float32] | type[np.float64]) -> ParticleClass:
if spatial_dtype not in [np.float32, np.float64]:
raise ValueError(f"spatial_dtype must be np.float32 or np.float64. Got {spatial_dtype=!r}")

Expand Down Expand Up @@ -177,7 +177,7 @@ def create_particle_data(
nparticles: int,
ngrids: int,
time_interval: TimeInterval,
initial: dict[str, np.array] | None = None,
initial: dict[str, np.ndarray] | None = None,
):
if initial is None:
initial = {}
Expand Down
10 changes: 5 additions & 5 deletions src/parcels/_core/particlefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,10 @@ def _write_particle_data(self, *, particle_data, pclass, time_interval, time, in
if self.create_new_zarrfile:
if self.chunks is None:
self._chunks = (nparticles, 1)
if (self._maxids > len(ids)) or (self._maxids > self.chunks[0]): # type: ignore[index]
arrsize = (self._maxids, self.chunks[1]) # type: ignore[index]
if (self._maxids > len(ids)) or (self._maxids > self.chunks[0]):
arrsize = (self._maxids, self.chunks[1])
else:
arrsize = (len(ids), self.chunks[1]) # type: ignore[index]
arrsize = (len(ids), self.chunks[1])
ds = xr.Dataset(
attrs=self.metadata,
coords={"trajectory": ("trajectory", pids), "obs": ("obs", np.arange(arrsize[1], dtype=np.int32))},
Expand All @@ -221,7 +221,7 @@ def _write_particle_data(self, *, particle_data, pclass, time_interval, time, in
data[ids, 0] = particle_data[var.name][indices_to_write]
dims = ["trajectory", "obs"]
ds[var.name] = xr.DataArray(data=data, dims=dims, attrs=attrs[var.name])
ds[var.name].encoding["chunks"] = self.chunks[0] if var.to_write == "once" else self.chunks # type: ignore[index]
ds[var.name].encoding["chunks"] = self.chunks[0] if var.to_write == "once" else self.chunks
ds.to_zarr(store, mode="w")
self._create_new_zarrfile = False
else:
Expand All @@ -234,7 +234,7 @@ def _write_particle_data(self, *, particle_data, pclass, time_interval, time, in
if len(once_ids) > 0:
Z[var.name].vindex[ids_once] = particle_data[var.name][indices_to_write_once]
else:
if max(obs) >= Z[var.name].shape[1]: # type: ignore[type-var]
if max(obs) >= Z[var.name].shape[1]:
self._extend_zarr_dims(Z[var.name], store, dtype=var.dtype, axis=1)
Z[var.name].vindex[ids, obs] = particle_data[var.name][indices_to_write]

Expand Down
2 changes: 1 addition & 1 deletion src/parcels/_core/utils/interpolation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from parcels._typing import Mesh

__all__ = [] # type: ignore
__all__ = []


def phi1D_lin(xsi: float) -> list[float]:
Expand Down
20 changes: 11 additions & 9 deletions src/parcels/_core/utils/sgrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import re
from collections.abc import Hashable, Iterable
from dataclasses import dataclass
from typing import Any, Literal, Protocol, Self, overload
from typing import Any, Literal, Protocol, Self, cast, overload

import xarray as xr

Expand Down Expand Up @@ -149,13 +149,13 @@ def __eq__(self, other: Any) -> bool:
return self.to_attrs() == other.to_attrs()

@classmethod
def from_attrs(cls, attrs):
def from_attrs(cls, attrs): # type: ignore[override]
try:
return cls(
cf_role=attrs["cf_role"],
topology_dimension=attrs["topology_dimension"],
node_dimensions=load_mappings(attrs["node_dimensions"]),
face_dimensions=load_mappings(attrs["face_dimensions"]),
node_dimensions=cast(tuple[Dim, Dim], load_mappings(attrs["node_dimensions"])),
face_dimensions=cast(tuple[DimDimPadding, DimDimPadding], load_mappings(attrs["face_dimensions"])),
node_coordinates=maybe_load_mappings(attrs.get("node_coordinates")),
vertical_dimensions=maybe_load_mappings(attrs.get("vertical_dimensions")),
)
Expand All @@ -176,7 +176,7 @@ def to_attrs(self) -> dict[str, str | int]:
return d

def rename(self, names_dict: dict[str, str]) -> Self:
return _metadata_rename(self, names_dict)
return cast(Self, _metadata_rename(self, names_dict))

def get_value_by_id(self, id: str) -> str:
"""In the SGRID specification for 2D grids, different parts of the spec are identified by different "ID"s.
Expand Down Expand Up @@ -262,13 +262,15 @@ def __eq__(self, other: Any) -> bool:
return self.to_attrs() == other.to_attrs()

@classmethod
def from_attrs(cls, attrs):
def from_attrs(cls, attrs): # type: ignore[override]
try:
return cls(
cf_role=attrs["cf_role"],
topology_dimension=attrs["topology_dimension"],
node_dimensions=load_mappings(attrs["node_dimensions"]),
volume_dimensions=load_mappings(attrs["volume_dimensions"]),
node_dimensions=cast(tuple[Dim, Dim, Dim], load_mappings(attrs["node_dimensions"])),
volume_dimensions=cast(
tuple[DimDimPadding, DimDimPadding, DimDimPadding], load_mappings(attrs["volume_dimensions"])
),
node_coordinates=maybe_load_mappings(attrs.get("node_coordinates")),
)
except Exception as e:
Expand All @@ -286,7 +288,7 @@ def to_attrs(self) -> dict[str, str | int]:
return d

def rename(self, dims_dict: dict[str, str]) -> Self:
return _metadata_rename(self, dims_dict)
return cast(Self, _metadata_rename(self, dims_dict))

def get_value_by_id(self, id: str) -> str:
"""In the SGRID specification for 3D grids, different parts of the spec are identified by different "ID"s.
Expand Down
2 changes: 1 addition & 1 deletion src/parcels/_core/uxgrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class UxGrid(BaseGrid):
for interpolation on unstructured grids.
"""

def __init__(self, grid: ux.grid.Grid, z: ux.UxDataArray, mesh) -> UxGrid:
def __init__(self, grid: ux.grid.Grid, z: ux.UxDataArray, mesh) -> None:
"""
Initializes the UxGrid with a uxarray grid and vertical coordinate array.

Expand Down
Loading
Loading