I'd like to contribute stubs for rasterio (and, with your guidance, possibly affine), and would appreciate guidance before opening the PR(s). Per CONTRIBUTING.md this seems large enough to warrant an issue first.
Context
- Rasterio maintainers decided not to have type hints in their code base
- A community
types-rasterio stub repo has existed for a while at kylebarron/types-rasterio. It was never published to PyPI, so the types-rasterio PyPI name is unclaimed.
- The maintainer has agreed to transfer the work, and I've updated and modernized those stubs to track the current
rasterio==1.5.x release.
rasterio depends heavily on affine — it's a hard runtime dependency, and affine.Affine appears in roughly 30 rasterio signatures (every transform / open() call / warp.reproject / WarpedVRT / Window helper). The rasterio stubs' usefulness is therefore tied to how typed affine is at the call site, which is the subject of the open questions below.
- A sibling
types-affine repo by the same maintainer is published on PyPI at 0.1.0; I've updated that locally to track affine==2.4.x. However, affine v3 is upcoming and will ship its own inline type hints — so affine stubs in typeshed would be obsoleted by the obsolete-since flow within months of v3's release.
- Neither
rasterio nor affine currently exists under stubs/ in typeshed; shapely is the closest existing sibling.
What is ready
For both packages:
- Stub files in the typeshed
<pkg>/<pkg>/*.pyi layout.
METADATA.toml (current format), @tests/stubtest_allowlist.txt.
partial-stub = true (Cython implementation details deferred to _typeshed.Incomplete where appropriate; entire public API surface covered).
- All of the following pass locally:
stubtest, mypy --strict against a runtime smoke script, pyright, ruff, flake8-pyi, plus per-overload positive/negative cases (currently in pytest-mypy-plugins YAML; I'll port to @tests/test_cases/check_*.py for the PR).
For rasterio specifically:
- 43 stub files covering rasterio 1.5's public API including the modules added since the previous community version:
abc, cache, stack, tools, shutil, plus the _-prefixed Cython modules transitively required by public re-exports.
- 12 PEP 702
@deprecated markers matching upstream's RasterioDeprecationWarning sites, including overload-based parameter deprecations (warp.transform_geom(antimeridian_*), windows.from_bounds(height/width/precision), merge(precision), features.geometry_window(north_up/rotated/pixel_precision), transform.TransformerBase.rowcol(precision), windows.WindowMethodsMixin.window(precision)). Whole-symbol @deprecated on CRS.is_valid, Window.round_shape, DatasetReaderBase.statistics, DatasetBase.is_tiled, env.hascreds, env.ensure_env_credentialled, io.FilePath, rasterio.path.{parse_path,vsi_path}.
For affine specifically: 1 stub file matching affine==2.4.0, plus the same @deprecated treatment on Affine.__rmul__ per upstream.
Open questions
1. affine.Affine reference strategy in the rasterio stubs
About 30 rasterio signatures touch affine.Affine (e.g. open(transform=), warp.reproject, WarpedVRT, every transform module helper). Options I've considered:
- (a)
from affine import Affine directly. Until affine v3 ships py.typed, type checkers see Affine = Any; once v3 lands the stubs automatically gain precision. Zero follow-up work.
- (b)
_typeshed.Incomplete everywhere Affine would appear, explicit about the lossy state. A follow-up PR swaps to Affine once affine v3 lands.
- (c) Local
_AffineLike Protocol inside the rasterio stubs (matrix-like a/b/c/d/e/f, xoff/yoff, __mul__). Slight precision gain over Incomplete, no follow-up needed when v3 lands.
- (d) Bundle affine stubs (see question 2) so
from affine import Affine resolves to typeshed-owned definitions immediately.
Do you have a preference?
2. Should typeshed accept affine stubs at all?
The runtime is small (one class, ~600 lines of source). The stubs would be useful for the months until affine v3 ships, but you'd then need to mark obsolete-since and rely on stubsabot to remove them after 6 months. Happy to submit if you want them, happy to skip if the short lifespan isn't worth the maintenance.
If skipped, I'll publish my affine stubs at the existing PyPI types-affine name as a final 0.2.0 bridge release and archive the GitHub repo.
3. PR shape
- One bundled PR for
stubs/rasterio/ and stubs/affine/, or
- Two separate PRs.
I'll defer to whichever is easier to review.
Known maintenance flags
- Cython introspection lies about parameter names in many of rasterio's
_-prefixed modules. I've handled this with broad allowlist regex (rasterio\._base.*, etc.) in @tests/stubtest_allowlist.txt. Open to alternatives.
partial-stub = true — the entire public API surface is covered, but a handful of internal Cython helpers are Incomplete.
- One deprecation can't be expressed via
@deprecated overload because **rpc_options swallows the deprecated kwarg in the modern overload (transform.rowcol(precision=) and transform.TransformMethodsMixin.index(precision=)). Documented inline; runtime warning is the only signal there.
Happy to provide more detail on any of the above. Thanks for considering!
I'd like to contribute stubs for rasterio (and, with your guidance, possibly affine), and would appreciate guidance before opening the PR(s). Per
CONTRIBUTING.mdthis seems large enough to warrant an issue first.Context
types-rasteriostub repo has existed for a while at kylebarron/types-rasterio. It was never published to PyPI, so thetypes-rasterioPyPI name is unclaimed.rasterio==1.5.xrelease.rasteriodepends heavily onaffine— it's a hard runtime dependency, andaffine.Affineappears in roughly 30 rasterio signatures (every transform /open()call /warp.reproject/WarpedVRT/Windowhelper). The rasterio stubs' usefulness is therefore tied to how typedaffineis at the call site, which is the subject of the open questions below.types-affinerepo by the same maintainer is published on PyPI at0.1.0; I've updated that locally to trackaffine==2.4.x. However, affine v3 is upcoming and will ship its own inline type hints — so affine stubs in typeshed would be obsoleted by theobsolete-sinceflow within months of v3's release.rasterionoraffinecurrently exists understubs/in typeshed;shapelyis the closest existing sibling.What is ready
For both packages:
<pkg>/<pkg>/*.pyilayout.METADATA.toml(current format),@tests/stubtest_allowlist.txt.partial-stub = true(Cython implementation details deferred to_typeshed.Incompletewhere appropriate; entire public API surface covered).stubtest,mypy --strictagainst a runtime smoke script,pyright,ruff,flake8-pyi, plus per-overload positive/negative cases (currently inpytest-mypy-pluginsYAML; I'll port to@tests/test_cases/check_*.pyfor the PR).For rasterio specifically:
abc,cache,stack,tools,shutil, plus the_-prefixed Cython modules transitively required by public re-exports.@deprecatedmarkers matching upstream'sRasterioDeprecationWarningsites, including overload-based parameter deprecations (warp.transform_geom(antimeridian_*),windows.from_bounds(height/width/precision),merge(precision),features.geometry_window(north_up/rotated/pixel_precision),transform.TransformerBase.rowcol(precision),windows.WindowMethodsMixin.window(precision)). Whole-symbol@deprecatedonCRS.is_valid,Window.round_shape,DatasetReaderBase.statistics,DatasetBase.is_tiled,env.hascreds,env.ensure_env_credentialled,io.FilePath,rasterio.path.{parse_path,vsi_path}.For affine specifically: 1 stub file matching
affine==2.4.0, plus the same@deprecatedtreatment onAffine.__rmul__per upstream.Open questions
1.
affine.Affinereference strategy in the rasterio stubsAbout 30 rasterio signatures touch
affine.Affine(e.g.open(transform=),warp.reproject,WarpedVRT, every transform module helper). Options I've considered:from affine import Affinedirectly. Until affine v3 shipspy.typed, type checkers seeAffine = Any; once v3 lands the stubs automatically gain precision. Zero follow-up work._typeshed.IncompleteeverywhereAffinewould appear, explicit about the lossy state. A follow-up PR swaps toAffineonce affine v3 lands._AffineLikeProtocol inside the rasterio stubs (matrix-likea/b/c/d/e/f,xoff/yoff,__mul__). Slight precision gain over Incomplete, no follow-up needed when v3 lands.from affine import Affineresolves to typeshed-owned definitions immediately.Do you have a preference?
2. Should typeshed accept affine stubs at all?
The runtime is small (one class, ~600 lines of source). The stubs would be useful for the months until affine v3 ships, but you'd then need to mark
obsolete-sinceand rely onstubsabotto remove them after 6 months. Happy to submit if you want them, happy to skip if the short lifespan isn't worth the maintenance.If skipped, I'll publish my affine stubs at the existing PyPI
types-affinename as a final0.2.0bridge release and archive the GitHub repo.3. PR shape
stubs/rasterio/andstubs/affine/, orI'll defer to whichever is easier to review.
Known maintenance flags
_-prefixed modules. I've handled this with broad allowlist regex (rasterio\._base.*, etc.) in@tests/stubtest_allowlist.txt. Open to alternatives.partial-stub = true— the entire public API surface is covered, but a handful of internal Cython helpers areIncomplete.@deprecatedoverload because**rpc_optionsswallows the deprecated kwarg in the modern overload (transform.rowcol(precision=)andtransform.TransformMethodsMixin.index(precision=)). Documented inline; runtime warning is the only signal there.Happy to provide more detail on any of the above. Thanks for considering!