Conversation
| lead_time=lead_time, | ||
| domain="conus", | ||
| file_type=file_type, | ||
| file_type=file_type, # ty: ignore[invalid-argument-type] |
There was a problem hiding this comment.
this seems typed correctly. maybe our item utility isn't right?
| lead_time=lead_time, | ||
| domain="conus", | ||
| file_type=file_type, | ||
| file_type=file_type, # ty: ignore[invalid-argument-type] |
There was a problem hiding this comment.
this seems typed correctly. maybe our item utility isn't right?
There was a problem hiding this comment.
wasn't able to get around this
| return gefs_file_type | ||
| # ty can't narrow through if/elif chain; remaining values are "a" | "b" | ||
| return gefs_file_type # ty: ignore[invalid-return-type] |
There was a problem hiding this comment.
can probably help type checker narrow and remove the ignore with an elif gefs_file_type == "a" or gefs_file_type == "b", and then an else: assert_never(gefs_file_type)
| # xarray's __getitem__ with a list returns Dataset, but ty stubs say DataArray | ||
| ds: xr.Dataset = self.template_ds[[v.name for v in self.data_vars]] # type: ignore[assignment] |
There was a problem hiding this comment.
| # xarray's __getitem__ with a list returns Dataset, but ty stubs say DataArray | |
| ds: xr.Dataset = self.template_ds[[v.name for v in self.data_vars]] # type: ignore[assignment] | |
| ds: xr.Dataset = self.template_ds[[v.name for v in self.data_vars]] # type: ignore[assignment] stubs are wrong |
| case _ as unreachable: | ||
| assert_never(unreachable) | ||
| assert_never(unreachable) # ty: ignore[type-assertion-failure] |
There was a problem hiding this comment.
this should work without an ignore
case _:
assert_never(gefs_file_type)
There was a problem hiding this comment.
it doesn't, but im going to live with that until ty implements this and then it should start telling us the type ignore is unused
86c253d to
2ad3ff0
Compare
Replace mypy with Astral's ty type checker throughout the project: - Replace mypy dependency with ty in pyproject.toml - Update ty configuration in pyproject.toml - Update pre-commit hook to use ty - Update GitHub Actions workflow to use ty - Update documentation (README.md, AGENTS.md/CLAUDE.md) - Update .vscode/extensions.json to remove mypy extension - Update .gitignore and .dockerignore for ty cache Remove unnecessary type: ignore comments that ty no longer needs: - ty has better type stubs for numba, numcodecs, fsspec, rasterio, yaml, kubernetes - ty handles pydantic's @computed_field properly Add explicit submodule imports for zarr.abc, zarr.storage, sentry_sdk.crons, numcodecs.abc to satisfy ty's stricter submodule attribute checking. Add targeted ty: ignore comments for: - numba's prange (not-iterable - prange is only iterable at runtime in @njit) - Complex type narrowing that ty can't verify through control flow - xarray's ds[[list]] returning DataArray instead of Dataset (stub limitation) Configure ty rules to treat some checks as warnings instead of errors: - invalid-method-override: Subclass return type covariance is valid Python - no-matching-overload: xarray stubs are incomplete - possibly-missing-attribute: For submodule access patterns ty finds issues mypy missed due to better type stubs, while still being fast. https://claude.ai/code/session_01RTS6T1SJHLNr4u6vinbqVg
b949cb8 to
7cc985b
Compare
Remove ABC and @AbstractMethod decorators from TemplateConfig, RegionJob, and DynamicalDataset base classes. The methods still raise NotImplementedError to enforce implementation at runtime, but ABC is no longer needed since: 1. Parameter names between base and subclass methods now match 2. ty doesn't require ABC for proper type checking of method overrides 3. This allows tests to instantiate base/intermediate classes directly https://claude.ai/code/session_01RTS6T1SJHLNr4u6vinbqVg
Remove typing.override decorators since they're not used consistently throughout the codebase. Add noqa: ARG002 comments for unused method arguments that are required by the parent class interface. https://claude.ai/code/session_01RTS6T1SJHLNr4u6vinbqVg
There was a problem hiding this comment.
Pull request overview
This PR migrates the project’s static type checking from mypy to ty, updating configuration, CI workflows, docs, and code to align with ty’s rules and diagnostics. It also makes small refactors and import adjustments to satisfy ty’s stricter module and attribute checking while keeping runtime behavior unchanged.
Changes:
- Replace mypy with ty across tooling: dev dependencies,
pyproject.tomlconfig, pre-commit hooks, GitHub Actions workflow, editor recommendations, and ignore patterns. - Update code and tests to remove mypy-specific
# type: ignore[...]comments, add ty-specific ignores, and introduce explicit imports / annotations (e.g., for numba, zarr, sentry, rasterio, Timedelta math) to satisfy ty while preserving semantics. - Refactor a few helper functions and expressions (e.g., XML parsing for CF standard names, Timedelta division, band-selection logic for rasterio) for clearer typing and better alignment with ty’s analysis.
Reviewed changes
Copilot reviewed 59 out of 61 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
uv.lock |
Drops mypy and related deps, adds ty and updates dev extras to reflect the new type checker. |
pyproject.toml |
Removes mypy and pydantic-mypy configuration, adds ty rules and dev dependency, and adjusts Ruff comments about PEP 695 generics. |
.pre-commit-config.yaml |
Swaps the local mypy hook for a ty hook running uv run ty check. |
.github/workflows/code-quality.yml |
Updates CI to run uv run ty check in place of uv run mypy. |
.gitignore / .dockerignore |
Generalizes the “mypy” ignore section to “type checkers” while retaining mypy cache patterns. |
.vscode/extensions.json |
Removes the mypy VS Code extension recommendation, leaving only Ruff. |
README.md |
Updates development tooling docs to mention ty instead of mypy and adjusts recommended commands. |
AGENTS.md |
Switches tool listing and example commands from mypy to ty and updates the code-style guideline to refer to ty ignores. |
tests/noaa/gfs/template_config_test.py |
Removes an obsolete mypy attr-defined ignore on coords.fget in tests. |
tests/noaa/gfs/forecast/template_config_test.py |
Drops mypy import-untyped ignore on rasterio in GFS forecast template tests. |
tests/noaa/gefs/forecast_35_day/template_config_test.py |
Same as above for GEFS 35-day forecast template tests. |
tests/example/template_config_test.py |
Updates a commented-out rasterio import to remove the mypy-specific ignore. |
tests/common/validation_test.py |
Replaces a broad zarr import with more targeted zarr.core.sync / zarr.storage imports to satisfy ty’s module/attribute checking. |
tests/common/test_storage.py |
Adds zarr.storage import to make types like LocalStore explicit for ty. |
tests/common/template_config_test.py |
Splits a Timedelta division into a temporary float result to align with ty’s assignment rules, then casts to int. |
tests/common/region_job_test.py |
Imports dask.array explicitly and removes unnecessary type ignores around dask.array.full; renames unused parameters with # noqa: ARG002. |
tests/common/dynamical_dataset_test.py |
Adds explicit imports for sentry_sdk.crons and zarr.errors; removes pydantic computed_field ignore annotations on test config properties. |
tests/common/datasets_cf_compliance_test.py |
Refactors XML parsing into an explicit loop that checks elements and text for None instead of relying on union-attr ignores. |
tests/common/common_template_config_subclasses_test.py |
Removes mypy-specific ignores on template_path reassignment and fixture return type. |
src/scripts/validation/compare_spatial.py |
Adds targeted # ty: ignore[...] comments for attributes on ref_data where ty’s analysis is too conservative. |
src/scripts/generate_manual_workflows.py |
Removes mypy import-untyped ignore from the yaml import. |
src/reformatters/noaa/hrrr/template_config.py |
Cleans up pydantic computed_field annotations by dropping mypy-specific prop-decorator ignores. |
src/reformatters/noaa/hrrr/region_job.py |
Removes mypy import-untyped on rasterio and rewrites GRIB band matching from a walrus-comprehension into a clearer loop with explicit list accumulation. |
src/reformatters/noaa/hrrr/forecast_48_hour/template_config.py |
Same computed_field cleanup; no runtime behavior change. |
src/reformatters/noaa/hrrr/forecast_48_hour/region_job.py |
Adds a # ty: ignore[invalid-argument-type] where ty can’t see a domain argument’s compatibility, without changing behavior. |
src/reformatters/noaa/hrrr/analysis/template_config.py |
Removes mypy ignores around computed fields on analysis templates. |
src/reformatters/noaa/hrrr/analysis/region_job.py |
Same domain file_type argument ty-ignore adjustment as the 48-hour forecast job. |
src/reformatters/noaa/gfs/region_job.py |
Drops mypy import ignore and expands GRIB band selection into an explicit loop mirroring the HRRR change. |
src/reformatters/noaa/gfs/forecast/template_config.py |
Cleans up computed_field decorators for dataset attributes, coords, and data_vars. |
src/reformatters/noaa/gfs/analysis/template_config.py |
Same computed_field cleanup and introduces a named-but-unused ds parameter with # noqa: ARG002 for ty. |
src/reformatters/noaa/gefs/read_data.py |
Removes mypy import ignore, explicitly imports rasterio.warp, and rewrites band matching to a loop consistent with other GRIB readers. |
src/reformatters/noaa/gefs/gefs_config_models.py |
Makes gefs_file_type handling more precise and type-safe by enumerating simple file types and using assert_never for impossible branches to satisfy ty. |
src/reformatters/noaa/gefs/forecast_35_day/template_config.py |
Adjusts append-dim chunk-size computation to go through a float variable (per ty) and removes computed_field mypy ignores. |
src/reformatters/noaa/gefs/analysis/template_config.py |
Same pattern as GEFS 35-day: chunk-size calculation via an intermediate float and computed_field cleanup. |
src/reformatters/example/template_config.py |
Updates example TemplateConfig to the new computed_field style without mypy-specific ignores. |
src/reformatters/example/region_job.py |
Removes an old mypy type-var ignore in commented example logic. |
src/reformatters/ecmwf/ifs_ens/forecast_15_day_0_25_degree/template_config.py |
Cleans computed_field annotations and keeps TemplateConfig integration compatible with ty. |
src/reformatters/ecmwf/ifs_ens/forecast_15_day_0_25_degree/region_job.py |
Removes mypy import-untyped ignore for rasterio. |
src/reformatters/dwd/icon_eu/forecast/template_config.py |
Uses computed_field without mypy ignores for the new DWD ICON-EU forecast template. |
src/reformatters/dwd/icon_eu/forecast/region_job.py |
Drops mypy ignore for rasterio and cleans up a commented example type-var ignore in update_template_with_results. |
src/reformatters/contrib/uarizona/swann/analysis/template_config.py |
Cleans computed_fields for the SWANN analysis TemplateConfig. |
src/reformatters/contrib/uarizona/swann/analysis/region_job.py |
Removes mypy import ignore on rasterio and updates an unused-parameter name to comply with linting; note: still uses from rasterio import rasterio, which is likely an incorrect import form and should be import rasterio. |
src/reformatters/contrib/noaa/ndvi_cdr/analysis/template_config.py |
Removes mypy-specific computed_field ignores for the NDVI CDR analysis template. |
src/reformatters/contrib/noaa/ndvi_cdr/analysis/region_job.py |
Drops mypy import-untyped on rasterio and renames an unused parameter with an ARG002 suppression. |
src/reformatters/contrib/noaa/ndvi_cdr/analysis/quality_flags.py |
Removes a no-any-return ignore now that return types are precise. |
src/reformatters/contrib/nasa/smap/level3_36km_v9/template_config.py |
Applies the same computed_field cleanup and uses ty-friendly typing for coords and data_vars. |
src/reformatters/contrib/nasa/smap/level3_36km_v9/region_job.py |
Drops mypy import-untyped from rasterio and marks an unused parameter appropriately. |
src/reformatters/common/zarr.py |
Adds zarr.core.sync import explicitly for sync_to_store, aligning with ty’s module-resolution expectations. |
src/reformatters/common/validation.py |
Adds explicit zarr.core.sync / zarr.storage imports and keeps validation helpers typed in a way that ty can understand. |
src/reformatters/common/update_progress_tracker.py |
Removes the mypy ignore on fsspec, imports fsspec.implementations.local, and uses it for a precise LocalFileSystem type check. |
src/reformatters/common/template_utils.py |
Drops mypy no-untyped-call ignores for dask.array.full and adds explicit zarr submodule imports for ty. |
src/reformatters/common/template_config.py |
Cleans all TemplateConfig computed_fields of mypy ignores, updates derive_coordinates signatures for ty, and makes append-dim chunk-size computation explicitly go through a float to satisfy ty’s Timedelta-division typing. |
src/reformatters/common/storage.py |
Removes mypy import ignore on fsspec, imports zarr submodules explicitly, and keeps StorageConfig.version as a computed_field without mypy-specific suppression. |
src/reformatters/common/region_job.py |
Removes a type-var ignore in update_template_with_results, adds a ty-ignore for the max(..., default=None) call, and explicitly annotates an xarray Dataset slice to work around stub issues. |
src/reformatters/common/kubernetes.py |
Drops the mypy import-untyped ignore on the Kubernetes client/config import. |
src/reformatters/common/interpolation.py |
Removes numba decorator type-ignore and introduces a ty-ignore on prange iteration, keeping the numba-accelerated interpolation logic intact. |
src/reformatters/common/dynamical_dataset.py |
Adds an explicit sentry_sdk.crons import and cleans computed_fields for ty compatibility. |
src/reformatters/common/deaccumulation.py |
Similar to interpolation: cleans numba decorator ignore and adds a ty-ignore on prange, preserving deaccumulation behavior. |
src/reformatters/common/config_models.py |
Reworks codecs_to_dicts to return only dicts (instead of sometimes codecs) and makes its input optional, aligning Encoding.filters with ty’s expectations. |
src/reformatters/common/binary_rounding.py |
Removes numba decorator type-ignore and adds a prange ty-ignore while keeping rounding logic unchanged. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
Love this 🙂 |
|
@JackKelly it checks the whole repo in 1.9s! (mypy is 18s). Im going to wait to update and merge it until #406 is on main to not create merge conflicts for you |
Summary
Migrate from mypy to ty as the primary type checker for the project. This includes updating all configuration files, CI/CD workflows, documentation, and code to use ty instead of mypy.
Key Changes
Configuration & Setup
pyproject.tomlto replacemypy~=1.18dependency withty~=0.0.14.gitignoreand.dockerignoreto ignore.ty/cache directory instead of mypy caches.pre-commit-config.yamlto runty checkinstead ofmypy.vscode/extensions.jsonCI/CD & Documentation
uv run ty checkinstead ofuv run mypyAGENTS.mdandREADME.mdwith ty commands and referencesCode Changes
# type: ignore[import-untyped]comments from untyped library imports (numba, kubernetes, rasterio, etc.) as ty handles these differently# type: ignore[...]comments with ty equivalents where needed (e.g.,# ty: ignore[not-iterable])@computed_fielddecorators to work with tyconfig_models.pyfor better type safety with codecs handlingimport zarr.abc.store,import sentry_sdk.crons) to satisfy ty's stricter module checkingdatasets_cf_compliance_test.py)Type Checking Configuration
possibly-missing-attribute(for submodule access likezarr.abc)no-matching-overload(for incomplete xarray stubs)invalid-method-override(for valid Python covariance patterns)Notable Details
https://claude.ai/code/session_01RTS6T1SJHLNr4u6vinbqVg