From ec5ea7ebb3e00997716680f833d7d43ecda63856 Mon Sep 17 00:00:00 2001 From: Brewster Malevich Date: Wed, 9 Sep 2026 16:16:54 -0700 Subject: [PATCH 1/3] Set stricter ruff, ty checks --- pyproject.toml | 10 +++++++++- uv.lock | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a6f41c7..6f148f0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,7 @@ tests = [ "numpy>=2.4.4", "pytest>=9.0.3", "pytest-cov>=7.1.0", - "ruff>=0.15.12", + "ruff>=0.16.0", "ty>=0.0.35", ] docs = ["mkdocstrings[python]>=1.0.4", "zensical>=0.0.41"] @@ -30,6 +30,7 @@ build-backend = "uv_build" [tool.ruff.lint] extend-select = [ + "ANN", "YTT", # flake8-2020 "B", # flake8-bugbear "C4", # flake8-comprehensions @@ -51,6 +52,7 @@ extend-select = [ "FURB", # refurb "RUF", ] +preview = true [tool.ruff.lint.isort] known-first-party = ["isku"] @@ -58,3 +60,9 @@ known-first-party = ["isku"] [tool.ruff.lint.flake8-tidy-imports] # Disallow all relative imports. ban-relative-imports = "all" + +[tool.ty.rules] +dynamic-function-decorator-return = "error" +missing-type-argument = "error" +possibly-unresolved-reference = "warn" +unsound-return-statement = "error" diff --git a/uv.lock b/uv.lock index a9a64d0..1f16b41 100644 --- a/uv.lock +++ b/uv.lock @@ -195,7 +195,7 @@ dev = [ { name = "prek", specifier = ">=0.3.13" }, { name = "pytest", specifier = ">=9.0.3" }, { name = "pytest-cov", specifier = ">=7.1.0" }, - { name = "ruff", specifier = ">=0.15.12" }, + { name = "ruff", specifier = ">=0.16.0" }, { name = "ty", specifier = ">=0.0.35" }, { name = "zensical", specifier = ">=0.0.41" }, ] @@ -207,7 +207,7 @@ tests = [ { name = "numpy", specifier = ">=2.4.4" }, { name = "pytest", specifier = ">=9.0.3" }, { name = "pytest-cov", specifier = ">=7.1.0" }, - { name = "ruff", specifier = ">=0.15.12" }, + { name = "ruff", specifier = ">=0.16.0" }, { name = "ty", specifier = ">=0.0.35" }, ] From 70f4fe6f34dae85dba9023c41021a452e3a0623a Mon Sep 17 00:00:00 2001 From: Brewster Malevich Date: Wed, 9 Sep 2026 16:46:54 -0700 Subject: [PATCH 2/3] Cleanup to make ty/ruff happy with stricter rules --- prek.toml | 2 +- src/isku/extract.py | 2 +- tests/smoke_test.py | 8 ++++---- tests/test_extraction.py | 12 ++++++------ tests/test_projection.py | 8 ++++---- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/prek.toml b/prek.toml index 708a17a..d5d1c8c 100644 --- a/prek.toml +++ b/prek.toml @@ -14,7 +14,7 @@ hooks = [ [[repos]] repo = "https://github.com/astral-sh/ruff-pre-commit" -rev = "v0.15.12" +rev = "v0.16.6" hooks = [ { id = "ruff-check", args = ["--fix", "--show-fixes"] }, { id = "ruff-format" }, diff --git a/src/isku/extract.py b/src/isku/extract.py index f3d37a9..e03db73 100644 --- a/src/isku/extract.py +++ b/src/isku/extract.py @@ -106,7 +106,7 @@ class GridWeightingRegions(RegionExtractor): RegionExtractor: Protocol for regionalizing, or extracting regions from a dataset. """ - def __init__(self, weights: xr.Dataset): + def __init__(self, weights: xr.Dataset) -> None: target_variables = ("lat", "lon", "weight", "region") missing_variables = [v for v in target_variables if v not in weights.variables] if missing_variables: diff --git a/tests/smoke_test.py b/tests/smoke_test.py index ac30793..c453dad 100644 --- a/tests/smoke_test.py +++ b/tests/smoke_test.py @@ -7,7 +7,7 @@ import isku -def test_basic_projection(): +def test_basic_projection() -> None: """ Basic test running build_projection_template() with project(). """ @@ -15,16 +15,16 @@ def test_basic_projection(): params = xr.Dataset({"ni": (["idx"], [1, 2, 3])}) expected = xr.Dataset({"impact": (["idx"], [13, 14, 15])}) - def _pre(x): + def _pre(x: xr.Dataset) -> xr.Dataset: out = xr.Dataset() out["foobar"] = x["foobar"] + 1 out["ni"] = x["ni"] return out - def _post(x): + def _post(x: xr.Dataset) -> xr.Dataset: return x[["impact"]] + 10 - def _model(x): + def _model(x: xr.Dataset) -> xr.Dataset: return (x["foobar"] * 2 + x["ni"]).to_dataset(name="impact") test_impact_model = isku.build_projection_template( diff --git a/tests/test_extraction.py b/tests/test_extraction.py index 9822312..9971eb8 100644 --- a/tests/test_extraction.py +++ b/tests/test_extraction.py @@ -8,7 +8,7 @@ import isku -def test_extract_regions(): +def test_extract_regions() -> None: """ Create simple extraction template and test basic region extraction. """ @@ -17,10 +17,10 @@ def test_extract_regions(): # Each of the transformation steps should add to the variable. # We'll know something basic is off if it doesn't add to `expected`. - def _pre(x): + def _pre(x: xr.Dataset) -> xr.Dataset: return x[["variable1"]] + 1 - def _post(x): + def _post(x: xr.Dataset) -> xr.Dataset: return x[["variable1"]] + 10 test_transform = isku.build_extraction_template(pre=_pre, post=_post) @@ -30,7 +30,7 @@ class FakeRegionalization(isku.RegionExtractor): Toy implementation of the RegionExtractor protocol """ - def extract_regions(self, ds): + def extract_regions(self, ds: xr.Dataset) -> xr.Dataset: # ruff: ignore[no-self-use] return ds[["variable1"]] + 2.5 output = isku.extract_regions( @@ -42,7 +42,7 @@ def extract_regions(self, ds): xr.testing.assert_allclose(output, expected) -def test_gridweightingregions_region_extraction(): +def test_gridweightingregions_region_extraction() -> None: """ Basic test calling GridWeightingRegions for regionalization with the RegionExtractor protocol. """ @@ -81,7 +81,7 @@ def test_gridweightingregions_region_extraction(): xr.testing.assert_allclose(actual, expected) -def test_gridweightingregions_extract_regions_with_extradim(): +def test_gridweightingregions_extract_regions_with_extradim() -> None: """ Basic GridWeightingRegions regionalization test, but if input data has extra time dim. """ diff --git a/tests/test_projection.py b/tests/test_projection.py index ce54ee7..3f44c41 100644 --- a/tests/test_projection.py +++ b/tests/test_projection.py @@ -7,7 +7,7 @@ from isku import build_projection_template, project -def test_basic_projection(): +def test_basic_projection() -> None: """ Basic test running build_projection_template() with project(). """ @@ -15,16 +15,16 @@ def test_basic_projection(): params = xr.Dataset({"ni": (["idx"], [1, 2, 3])}) expected = xr.Dataset({"impact": (["idx"], [13, 14, 15])}) - def _pre(x): + def _pre(x: xr.Dataset) -> xr.Dataset: out = xr.Dataset() out["foobar"] = x["foobar"] + 1 out["ni"] = x["ni"] return out - def _post(x): + def _post(x: xr.Dataset) -> xr.Dataset: return x[["impact"]] + 10 - def _model(x): + def _model(x: xr.Dataset) -> xr.Dataset: return (x["foobar"] * 2 + x["ni"]).to_dataset(name="impact") test_impact_model = build_projection_template( From 49b001dd59045446382ca20ff16d1c48f5db94a7 Mon Sep 17 00:00:00 2001 From: Brewster Malevich Date: Wed, 9 Sep 2026 16:50:53 -0700 Subject: [PATCH 3/3] Add changelog entry --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index de9b35a..9432d8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Releases from v0.4.0 onwards are now archived with a DOI. A badge at the top of the README shows the DOI of the last release. ([@brews](https://github.com/brews), [PR#94](https://github.com/ClimateImpactLab/isku/pull/94)) +### Changed + +- Stricter type checking from ruff/ty. ([@brews](https://github.com/brews), [PR#125](https://github.com/ClimateImpactLab/isku/pull/125)) + ## [0.4.0] - 2026-07-24 ### Added