From 05311006b570ff356861cf691c0ee67fccc09d68 Mon Sep 17 00:00:00 2001 From: Thomas Maschler Date: Mon, 8 Jun 2026 12:31:30 -0400 Subject: [PATCH 1/7] [rasterio] Add stubs for rasterio 1.5 Covers the public rasterio 1.5.x API plus the private Cython modules that are transitively required by public re-exports. `partial-stub = true` (a handful of internal Cython helpers are `Incomplete`). `affine.Affine` is referenced through a single stubs-only indirection module (`rasterio._affine_types`) that aliases `Affine` to `Any` until affine ships its own `py.typed` (planned for v3), per discussion in issue #15870. When affine v3 lands, replacing the body of `_affine_types.pyi` with `from affine import Affine as Affine` will restore precision package-wide in a single edit. PEP 702 `@deprecated` markers cover every documented `RasterioDeprecationWarning` site, including the 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) and whole-symbol cases (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}). Closes #15870 (in part; see issue for the affine-stubs decision). --- stubs/rasterio/@tests/stubtest_allowlist.txt | 27 +++ stubs/rasterio/@tests/test_cases/check_crs.py | 17 ++ .../@tests/test_cases/check_dataset.py | 34 +++ .../rasterio/@tests/test_cases/check_open.py | 26 +++ .../@tests/test_cases/check_transform_geom.py | 21 ++ .../@tests/test_cases/check_windows.py | 22 ++ stubs/rasterio/METADATA.toml | 20 ++ stubs/rasterio/rasterio/__init__.pyi | 134 +++++++++++ stubs/rasterio/rasterio/_affine_types.pyi | 7 + stubs/rasterio/rasterio/_base.pyi | 176 +++++++++++++++ stubs/rasterio/rasterio/_env.pyi | 41 ++++ stubs/rasterio/rasterio/_err.pyi | 43 ++++ stubs/rasterio/rasterio/_features.pyi | 30 +++ stubs/rasterio/rasterio/_filepath.pyi | 6 + stubs/rasterio/rasterio/_io.pyi | 212 ++++++++++++++++++ stubs/rasterio/rasterio/_path.pyi | 35 +++ stubs/rasterio/rasterio/_show_versions.pyi | 1 + stubs/rasterio/rasterio/_transform.pyi | 16 ++ stubs/rasterio/rasterio/_typing.pyi | 15 ++ stubs/rasterio/rasterio/_version.pyi | 5 + stubs/rasterio/rasterio/_vsiopener.pyi | 20 ++ stubs/rasterio/rasterio/_warp.pyi | 135 +++++++++++ stubs/rasterio/rasterio/abc.pyi | 1 + stubs/rasterio/rasterio/cache.pyi | 2 + stubs/rasterio/rasterio/control.pyi | 46 ++++ stubs/rasterio/rasterio/coords.pyi | 11 + stubs/rasterio/rasterio/crs.pyi | 79 +++++++ stubs/rasterio/rasterio/drivers.pyi | 8 + stubs/rasterio/rasterio/dtypes.pyi | 40 ++++ stubs/rasterio/rasterio/enums.pyi | 128 +++++++++++ stubs/rasterio/rasterio/env.pyi | 100 +++++++++ stubs/rasterio/rasterio/errors.pyi | 40 ++++ stubs/rasterio/rasterio/features.pyi | 91 ++++++++ stubs/rasterio/rasterio/fill.pyi | 11 + stubs/rasterio/rasterio/io.pyi | 93 ++++++++ stubs/rasterio/rasterio/mask.pyi | 33 +++ stubs/rasterio/rasterio/merge.pyi | 63 ++++++ stubs/rasterio/rasterio/path.pyi | 18 ++ stubs/rasterio/rasterio/plot.pyi | 50 +++++ stubs/rasterio/rasterio/profiles.pyi | 13 ++ stubs/rasterio/rasterio/rpc.pyi | 43 ++++ stubs/rasterio/rasterio/sample.pyi | 16 ++ stubs/rasterio/rasterio/session.pyi | 109 +++++++++ stubs/rasterio/rasterio/shutil.pyi | 13 ++ stubs/rasterio/rasterio/stack.pyi | 28 +++ stubs/rasterio/rasterio/tools.pyi | 19 ++ stubs/rasterio/rasterio/transform.pyi | 119 ++++++++++ stubs/rasterio/rasterio/vrt.pyi | 16 ++ stubs/rasterio/rasterio/warp.pyi | 107 +++++++++ stubs/rasterio/rasterio/windows.pyi | 100 +++++++++ 50 files changed, 2440 insertions(+) create mode 100644 stubs/rasterio/@tests/stubtest_allowlist.txt create mode 100644 stubs/rasterio/@tests/test_cases/check_crs.py create mode 100644 stubs/rasterio/@tests/test_cases/check_dataset.py create mode 100644 stubs/rasterio/@tests/test_cases/check_open.py create mode 100644 stubs/rasterio/@tests/test_cases/check_transform_geom.py create mode 100644 stubs/rasterio/@tests/test_cases/check_windows.py create mode 100644 stubs/rasterio/METADATA.toml create mode 100644 stubs/rasterio/rasterio/__init__.pyi create mode 100644 stubs/rasterio/rasterio/_affine_types.pyi create mode 100644 stubs/rasterio/rasterio/_base.pyi create mode 100644 stubs/rasterio/rasterio/_env.pyi create mode 100644 stubs/rasterio/rasterio/_err.pyi create mode 100644 stubs/rasterio/rasterio/_features.pyi create mode 100644 stubs/rasterio/rasterio/_filepath.pyi create mode 100644 stubs/rasterio/rasterio/_io.pyi create mode 100644 stubs/rasterio/rasterio/_path.pyi create mode 100644 stubs/rasterio/rasterio/_show_versions.pyi create mode 100644 stubs/rasterio/rasterio/_transform.pyi create mode 100644 stubs/rasterio/rasterio/_typing.pyi create mode 100644 stubs/rasterio/rasterio/_version.pyi create mode 100644 stubs/rasterio/rasterio/_vsiopener.pyi create mode 100644 stubs/rasterio/rasterio/_warp.pyi create mode 100644 stubs/rasterio/rasterio/abc.pyi create mode 100644 stubs/rasterio/rasterio/cache.pyi create mode 100644 stubs/rasterio/rasterio/control.pyi create mode 100644 stubs/rasterio/rasterio/coords.pyi create mode 100644 stubs/rasterio/rasterio/crs.pyi create mode 100644 stubs/rasterio/rasterio/drivers.pyi create mode 100644 stubs/rasterio/rasterio/dtypes.pyi create mode 100644 stubs/rasterio/rasterio/enums.pyi create mode 100644 stubs/rasterio/rasterio/env.pyi create mode 100644 stubs/rasterio/rasterio/errors.pyi create mode 100644 stubs/rasterio/rasterio/features.pyi create mode 100644 stubs/rasterio/rasterio/fill.pyi create mode 100644 stubs/rasterio/rasterio/io.pyi create mode 100644 stubs/rasterio/rasterio/mask.pyi create mode 100644 stubs/rasterio/rasterio/merge.pyi create mode 100644 stubs/rasterio/rasterio/path.pyi create mode 100644 stubs/rasterio/rasterio/plot.pyi create mode 100644 stubs/rasterio/rasterio/profiles.pyi create mode 100644 stubs/rasterio/rasterio/rpc.pyi create mode 100644 stubs/rasterio/rasterio/sample.pyi create mode 100644 stubs/rasterio/rasterio/session.pyi create mode 100644 stubs/rasterio/rasterio/shutil.pyi create mode 100644 stubs/rasterio/rasterio/stack.pyi create mode 100644 stubs/rasterio/rasterio/tools.pyi create mode 100644 stubs/rasterio/rasterio/transform.pyi create mode 100644 stubs/rasterio/rasterio/vrt.pyi create mode 100644 stubs/rasterio/rasterio/warp.pyi create mode 100644 stubs/rasterio/rasterio/windows.pyi diff --git a/stubs/rasterio/@tests/stubtest_allowlist.txt b/stubs/rasterio/@tests/stubtest_allowlist.txt new file mode 100644 index 000000000000..f3203434f693 --- /dev/null +++ b/stubs/rasterio/@tests/stubtest_allowlist.txt @@ -0,0 +1,27 @@ +# Stubtest allowlist for rasterio. +# +# Each line is a regex; matches are *not* reported by stubtest. Format mirrors +# python/typeshed so the file can move into `stubs/rasterio/@tests/` unchanged. +# Most "item present at runtime but missing from stub" cases are silenced by +# the `--ignore-missing-stub` flag (we mark the package `partial-stub = true` +# in METADATA.toml). This file lists per-symbol exceptions that aren't covered +# by that flag. + +# Stubs-only helper modules (no runtime counterpart). +rasterio\._typing +rasterio\._affine_types + +# Stubs-only type aliases used in signatures only. +rasterio\.features\.Geometry +rasterio\.merge\.MethodFunction + +# Cython extension classes need `@disjoint_base` and have Cython-introspected +# parameter names that sometimes disagree with the stub. We hide these for the +# subset of private modules that still surface drift after the Public-API +# reconciliation. Users typically call positionally, so this is low-risk. +rasterio\._base.* +rasterio\._io.* +rasterio\._env.* +rasterio\._err.* +rasterio\._features.* +rasterio\._transform.* diff --git a/stubs/rasterio/@tests/test_cases/check_crs.py b/stubs/rasterio/@tests/test_cases/check_crs.py new file mode 100644 index 000000000000..450f73736a5e --- /dev/null +++ b/stubs/rasterio/@tests/test_cases/check_crs.py @@ -0,0 +1,17 @@ +"""Verify `rasterio.crs.CRS` factory return types and arg validation.""" + +from __future__ import annotations + +from typing_extensions import assert_type + +from rasterio.crs import CRS + +# All factory staticmethods return `CRS`. +assert_type(CRS.from_epsg(4326), CRS) +assert_type(CRS.from_string("EPSG:4326"), CRS) +assert_type(CRS.from_wkt("..."), CRS) +assert_type(CRS.from_authority("EPSG", 4326), CRS) +assert_type(CRS.from_user_input(4326), CRS) + +# from_epsg expects int | str, not float. +CRS.from_epsg(4326.0) # type: ignore[arg-type] diff --git a/stubs/rasterio/@tests/test_cases/check_dataset.py b/stubs/rasterio/@tests/test_cases/check_dataset.py new file mode 100644 index 000000000000..1564c99b8a1b --- /dev/null +++ b/stubs/rasterio/@tests/test_cases/check_dataset.py @@ -0,0 +1,34 @@ +"""Verify the inferred property types on a `DatasetReader`.""" + +from __future__ import annotations + +from typing import Any +from typing_extensions import assert_type + +from numpy.typing import NDArray +from rasterio.coords import BoundingBox +from rasterio.crs import CRS +from rasterio.io import DatasetReader +from rasterio.profiles import Profile + + +def check_props(reader: DatasetReader) -> None: + assert_type(reader.crs, CRS) + # NOTE: `reader.transform` is typed via the stubs-only + # `rasterio._affine_types.Affine = Any` indirection until affine + # ships its own `py.typed` (v3). No `assert_type` here because the + # alias is `Any`; once affine v3 lands and the indirection swaps to + # `from affine import Affine`, an `assert_type(reader.transform, + # Affine)` line should be reinstated. + assert_type(reader.bounds, BoundingBox) + assert_type(reader.profile, Profile) + assert_type(reader.count, int) + assert_type(reader.width, int) + assert_type(reader.height, int) + assert_type(reader.shape, tuple[int, int]) + assert_type(reader.dtypes, tuple[str, ...]) + assert_type(reader.indexes, tuple[int, ...]) + assert_type(reader.nodata, float | None) + assert_type(reader.read(1), NDArray[Any]) + assert_type(reader.read_crs(), CRS | None) + assert_type(reader.tags(), dict[str, str]) diff --git a/stubs/rasterio/@tests/test_cases/check_open.py b/stubs/rasterio/@tests/test_cases/check_open.py new file mode 100644 index 000000000000..2517b719168a --- /dev/null +++ b/stubs/rasterio/@tests/test_cases/check_open.py @@ -0,0 +1,26 @@ +"""Verify `rasterio.open` overloads route to the right return type.""" + +from __future__ import annotations + +from typing_extensions import assert_type + +import rasterio +from rasterio.io import DatasetReader, DatasetWriter + +# Default mode is "r" → DatasetReader +assert_type(rasterio.open("foo.tif"), DatasetReader) +assert_type(rasterio.open("foo.tif", "r"), DatasetReader) + +# Write/update modes → DatasetWriter +assert_type(rasterio.open("foo.tif", "w", driver="GTiff"), DatasetWriter) +assert_type(rasterio.open("foo.tif", "r+"), DatasetWriter) +assert_type(rasterio.open("foo.tif", "w+"), DatasetWriter) + + +def _opaque_mode(mode: str) -> None: + # When `mode` is opaque str, the union overload is picked. + assert_type(rasterio.open("foo.tif", mode), DatasetReader | DatasetWriter) + + +# An int path is not a valid `fp`; the overload check rejects it. +rasterio.open(123) # type: ignore[call-overload] diff --git a/stubs/rasterio/@tests/test_cases/check_transform_geom.py b/stubs/rasterio/@tests/test_cases/check_transform_geom.py new file mode 100644 index 000000000000..1295d7debcaf --- /dev/null +++ b/stubs/rasterio/@tests/test_cases/check_transform_geom.py @@ -0,0 +1,21 @@ +"""Verify the deprecated-overload routing on `rasterio.warp.transform_geom`.""" + +from __future__ import annotations + +from rasterio.crs import CRS +from rasterio.warp import transform_geom + +src = CRS.from_epsg(4326) +dst = CRS.from_epsg(3857) +geom: dict[str, object] = {"type": "Point", "coordinates": [0.0, 0.0]} + +# Modern overload — no deprecated kwargs. +transform_geom(src, dst, geom) +transform_geom(src, dst, geom, precision=2) + +# Legacy overload — `antimeridian_*` kwargs are deprecated no-ops since +# GDAL 2.2. The @deprecated marker on the overload is carried in the stub; +# typeshed's regr_test does not opt into `enable_error_code = deprecated` +# so this call type-checks here, but downstream consumers see the warning. +transform_geom(src, dst, geom, antimeridian_cutting=True) +transform_geom(src, dst, geom, antimeridian_offset=10.0) diff --git a/stubs/rasterio/@tests/test_cases/check_windows.py b/stubs/rasterio/@tests/test_cases/check_windows.py new file mode 100644 index 000000000000..17374562f746 --- /dev/null +++ b/stubs/rasterio/@tests/test_cases/check_windows.py @@ -0,0 +1,22 @@ +"""Verify `rasterio.windows.Window` constructors and the from_bounds overload.""" + +from __future__ import annotations + +from typing_extensions import assert_type + +from rasterio.transform import from_origin +from rasterio.windows import Window, from_bounds + +# Constructors. +w = Window(0, 0, 10, 10) +assert_type(w, Window) +assert_type(Window.from_slices(slice(0, 5), slice(0, 5)), Window) +assert_type(w.intersection(w), Window) +assert_type(w.todict(), dict[str, float]) + +# from_bounds — modern overload (no deprecated kwargs). +t = from_origin(0.0, 0.0, 1.0, 1.0) +assert_type(from_bounds(0, 0, 1, 1, t), Window) + +# Negative widths are accepted at the type level; runtime validates. +assert_type(Window(0, 0, -1, -1), Window) diff --git a/stubs/rasterio/METADATA.toml b/stubs/rasterio/METADATA.toml new file mode 100644 index 000000000000..9f7ffa9f7378 --- /dev/null +++ b/stubs/rasterio/METADATA.toml @@ -0,0 +1,20 @@ +version = "1.5.*" +upstream-repository = "https://github.com/rasterio/rasterio" +# rasterio 1.5 itself requires Python 3.12+, so we mirror its floor. +requires-python = ">=3.12" +# `numpy` and `click` ship their own `py.typed`; listed by their PyPI runtime +# name. `affine` is referenced only through the stubs-only +# `rasterio._affine_types` indirection (Affine -> Any), so no stub or +# runtime dependency on affine is needed here. +dependencies = ["numpy>=2", "click>=8"] +# Not every internal symbol is typed (notably much of the Cython extension +# layer), but the entire public API surface is covered. +partial-stub = true + +[tool.stubtest] +# Mirror the package-level partial-stub flag — internal Cython attributes +# (`__attrs_*`, `__reduce_cython__`, etc.) are not enumerated in the stubs. +ignore-missing-stub = true +stubtest-dependencies = ["rasterio==1.5.*"] +apt-dependencies = ["libgdal-dev", "gdal-bin"] +brew-dependencies = ["gdal"] diff --git a/stubs/rasterio/rasterio/__init__.pyi b/stubs/rasterio/rasterio/__init__.pyi new file mode 100644 index 000000000000..f1bf2d1276a7 --- /dev/null +++ b/stubs/rasterio/rasterio/__init__.pyi @@ -0,0 +1,134 @@ +import logging +import os +from collections.abc import Callable, Sequence +from typing import Any, Final, Literal, NamedTuple, TypeAlias, overload + +from numpy.typing import DTypeLike, NDArray +from rasterio._base import DatasetBase as DatasetBase +from rasterio._io import Statistics as Statistics +from rasterio._path import _parse_path as _parse_path, _UnparsedPath as _UnparsedPath +from rasterio._show_versions import show_versions as show_versions +from rasterio._typing import AnyDataset, CRSInput +from rasterio._version import ( + gdal_version as gdal_version, + get_geos_version as get_geos_version, + get_proj_version as get_proj_version, +) +from rasterio._vsiopener import _opener_registration as _opener_registration +from rasterio.crs import CRS as CRS +from rasterio.drivers import driver_from_extension as driver_from_extension, is_blacklisted as is_blacklisted +from rasterio.dtypes import ( + bool_ as bool_, + check_dtype as check_dtype, + complex_ as complex_, + complex_int16 as complex_int16, + float16 as float16, + float32 as float32, + float64 as float64, + int8 as int8, + int16 as int16, + int32 as int32, + int64 as int64, + sbyte as sbyte, + ubyte as ubyte, + uint8 as uint8, + uint16 as uint16, + uint32 as uint32, + uint64 as uint64, +) +from rasterio.env import Env as Env, ensure_env_with_credentials as ensure_env_with_credentials +from rasterio.errors import ( + DriverCapabilityError as DriverCapabilityError, + RasterioDeprecationWarning as RasterioDeprecationWarning, + RasterioIOError as RasterioIOError, +) +from rasterio.io import ( + BufferedDatasetWriter as BufferedDatasetWriter, + DatasetReader as DatasetReader, + DatasetWriter as DatasetWriter, + FilePath as FilePath, + MemoryFile as MemoryFile, + get_writer_for_driver as get_writer_for_driver, + get_writer_for_path as get_writer_for_path, +) +from rasterio.profiles import default_gtiff_profile as default_gtiff_profile +from rasterio.transform import Affine as Affine, guard_transform as guard_transform + +__all__ = ["CRS", "Band", "Env", "band", "open", "pad"] + +__version__: Final[str] +__gdal_version__: Final[str] +__proj_version__: Final[str] +__geos_version__: Final[str] + +have_vsi_plugin: Final[bool] +log: logging.Logger + +_Fp: TypeAlias = str | os.PathLike[str] | MemoryFile | FilePath + +@overload +def open( + fp: _Fp, + mode: Literal["r"] = "r", + driver: str | Sequence[str] | None = None, + width: int | None = None, + height: int | None = None, + count: int | None = None, + crs: CRSInput | None = None, + transform: Affine | None = None, + dtype: DTypeLike | None = None, + nodata: float | None = None, + sharing: bool = False, + thread_safe: bool = False, + opener: Callable[..., Any] | None = None, + **kwargs: Any, +) -> DatasetReader: ... +@overload +def open( + fp: _Fp, + mode: Literal["r+", "w", "w+"], + driver: str | Sequence[str] | None = None, + width: int | None = None, + height: int | None = None, + count: int | None = None, + crs: CRSInput | None = None, + transform: Affine | None = None, + dtype: DTypeLike | None = None, + nodata: float | None = None, + sharing: bool = False, + thread_safe: bool = False, + opener: Callable[..., Any] | None = None, + **kwargs: Any, +) -> DatasetWriter: ... +@overload +def open( + fp: _Fp, + mode: str = "r", + driver: str | Sequence[str] | None = None, + width: int | None = None, + height: int | None = None, + count: int | None = None, + crs: CRSInput | None = None, + transform: Affine | None = None, + dtype: DTypeLike | None = None, + nodata: float | None = None, + sharing: bool = False, + thread_safe: bool = False, + opener: Callable[..., Any] | None = None, + **kwargs: Any, +) -> DatasetReader | DatasetWriter: ... + +class Band(NamedTuple): + ds: AnyDataset + bidx: int | Sequence[int] + dtype: str + shape: tuple[int, ...] + +def band(ds: AnyDataset, bidx: int | Sequence[int]) -> Band: ... +def pad( + array: NDArray[Any], + transform: Affine, + pad_width: int, + mode: str | Callable[..., Any] | None = None, + **kwargs: Any, +) -> tuple[NDArray[Any], Affine]: ... diff --git a/stubs/rasterio/rasterio/_affine_types.pyi b/stubs/rasterio/rasterio/_affine_types.pyi new file mode 100644 index 000000000000..112557c71595 --- /dev/null +++ b/stubs/rasterio/rasterio/_affine_types.pyi @@ -0,0 +1,7 @@ +# Stubs-only indirection for `affine` package types used in rasterio +# signatures. Until affine ships its own `py.typed` (planned for v3), +# `Affine` is exposed as `Any`. When affine v3 lands, replace the body +# of this module with `from affine import Affine as Affine`. +from typing import Any, TypeAlias + +Affine: TypeAlias = Any diff --git a/stubs/rasterio/rasterio/_base.pyi b/stubs/rasterio/rasterio/_base.pyi new file mode 100644 index 000000000000..6ad153393b2f --- /dev/null +++ b/stubs/rasterio/rasterio/_base.pyi @@ -0,0 +1,176 @@ +import logging +import os +from collections.abc import Iterable, Sequence +from types import TracebackType +from typing import Any, Final, Self +from typing_extensions import deprecated + +from rasterio._affine_types import Affine +from rasterio._path import _ParsedPath, _UnparsedPath +from rasterio._typing import Colormap, CRSInput +from rasterio.control import GroundControlPoint +from rasterio.coords import BoundingBox +from rasterio.crs import CRS +from rasterio.enums import ColorInterp, Compression, Interleaving, MaskFlags, PhotometricInterp +from rasterio.profiles import Profile +from rasterio.rpc import RPC +from rasterio.windows import Window + +log: Final[logging.Logger] + +def get_dataset_driver(path: str) -> str: ... +def driver_supports_mode(drivername: str, creation_mode: str) -> bool: ... +def driver_can_create(drivername: str) -> bool: ... +def driver_can_create_copy(drivername: str) -> bool: ... + +# Re-imported from `rasterio.transform` at runtime. +def tastes_like_gdal(seq: Affine | Sequence[float]) -> bool: ... +def _raster_driver_extensions() -> dict[str, str]: ... +def _can_create_osr(crs: CRSInput) -> bool: ... +def _transform( + src_crs: CRSInput, + dst_crs: CRSInput, + xs: Sequence[float], + ys: Sequence[float], + zs: Sequence[float] | None, +) -> tuple[list[float], list[float], list[float]]: ... + +class DatasetBase: + name: str + mode: str + options: dict[str, Any] + width: int + height: int + shape: tuple[int, int] + driver: str + + def __init__( + self, + path: str | os.PathLike[str] | _ParsedPath | _UnparsedPath | None = None, + driver: str | Sequence[str] | None = None, + sharing: bool = False, + thread_safe: bool = False, + **kwargs: Any, + ) -> None: ... + def __enter__(self) -> Self: ... + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: ... + def read_crs(self) -> CRS | None: ... + def read_transform(self) -> list[float]: ... + def start(self) -> None: ... + def stop(self) -> None: ... + def close(self) -> None: ... + @property + def closed(self) -> bool: ... + @property + def count(self) -> int: ... + @property + def indexes(self) -> tuple[int, ...]: ... + @property + def dtypes(self) -> tuple[str, ...]: ... + @property + def block_shapes(self) -> tuple[tuple[int, int], ...]: ... + def get_nodatavals(self) -> tuple[float | None, ...]: ... + @property + def nodatavals(self) -> tuple[float | None, ...]: ... + @property + def nodata(self) -> float | None: ... + @nodata.setter + def nodata(self, value: float | None) -> None: ... + @property + def mask_flag_enums(self) -> tuple[list[MaskFlags], ...]: ... + @property + def crs(self) -> CRS: ... + @crs.setter + def crs(self, value: CRSInput) -> None: ... + @property + def descriptions(self) -> tuple[str | None, ...]: ... + @descriptions.setter + def descriptions(self, value: Sequence[str | None]) -> None: ... + def write_transform(self, transform: Sequence[float]) -> None: ... + @property + def transform(self) -> Affine: ... + @transform.setter + def transform(self, value: Affine) -> None: ... + @property + def offsets(self) -> tuple[float, ...]: ... + @offsets.setter + def offsets(self, value: Sequence[float]) -> None: ... + @property + def scales(self) -> tuple[float, ...]: ... + @scales.setter + def scales(self, value: Sequence[float]) -> None: ... + @property + def units(self) -> tuple[str | None, ...]: ... + @units.setter + def units(self, value: Sequence[str | None]) -> None: ... + def block_window(self, bidx: int, i: int, j: int) -> Window: ... + def block_size(self, bidx: int, i: int, j: int) -> int: ... + def block_windows(self, bidx: int = 0) -> Iterable[tuple[tuple[int, int], Window]]: ... + @property + def bounds(self) -> BoundingBox: ... + @property + def res(self) -> tuple[float, float]: ... + @property + def meta(self) -> dict[str, Any]: ... + @property + def compression(self) -> Compression | None: ... + @property + def interleaving(self) -> Interleaving | None: ... + @property + def photometric(self) -> PhotometricInterp | None: ... + @property + @deprecated("DatasetBase.is_tiled will be removed in a future rasterio release; inspect block_shapes / profile directly.") + def is_tiled(self) -> bool: ... + @property + def profile(self) -> Profile: ... + def lnglat(self) -> tuple[float, float]: ... + def get_transform(self) -> list[float]: ... + @property + def subdatasets(self) -> list[str]: ... + def tag_namespaces(self, bidx: int = 0) -> list[str]: ... + def tags(self, bidx: int = 0, ns: str | None = None) -> dict[str, str]: ... + def get_tag_item( + self, + ns: str, + dm: str | None = None, + bidx: int = 0, + ovr: int | None = None, + ) -> str | None: ... + @property + def colorinterp(self) -> tuple[ColorInterp, ...]: ... + @colorinterp.setter + def colorinterp(self, value: Sequence[ColorInterp]) -> None: ... + def colormap(self, bidx: int) -> Colormap: ... + def overviews(self, bidx: int) -> list[int]: ... + def checksum(self, bidx: int, window: Window | None = None) -> int: ... + def get_gcps(self) -> tuple[list[GroundControlPoint], CRS]: ... + @property + def gcps(self) -> tuple[list[GroundControlPoint], CRS]: ... + @gcps.setter + def gcps(self, value: tuple[Sequence[GroundControlPoint], CRSInput]) -> None: ... + @property + def rpcs(self) -> RPC | None: ... + @rpcs.setter + def rpcs(self, value: RPC | None) -> None: ... + @property + def files(self) -> list[str]: ... + +# Module-level helpers used internally by other rasterio modules. +_GDAL_AT_LEAST_3_10: Final[bool] + +# Re-exported numpy dtype name constants (mirrors `rasterio.dtypes`); kept for +# compatibility with code that imports them from `rasterio._base`. +complex64: Final[str] +complex128: Final[str] +complex_int16: Final[str] +float32: Final[str] +float64: Final[str] +int16: Final[str] + +# The path-parsing helper; re-exported here for backwards compatibility. +def _parse_path(path: str): ... diff --git a/stubs/rasterio/rasterio/_env.pyi b/stubs/rasterio/rasterio/_env.pyi new file mode 100644 index 000000000000..4d5592bebbfe --- /dev/null +++ b/stubs/rasterio/rasterio/_env.pyi @@ -0,0 +1,41 @@ +from contextlib import AbstractContextManager +from typing import Any, Final + +ca_bundle: Final[str] +code_map: Final[dict[int, int]] +level_map: Final[dict[int, int]] + +def gdal_version() -> str: ... +def get_gdal_config(key: str, normalize: bool = True) -> Any: ... +def set_gdal_config(key: str, val: Any, normalize: bool = True) -> None: ... +def del_gdal_config(key: str) -> None: ... +def get_gdal_data() -> str | None: ... +def get_proj_data_search_paths() -> list[str]: ... +def set_proj_data_search_path(path: str) -> None: ... +def driver_count() -> int: ... +def catch_errors() -> AbstractContextManager[None]: ... + +class ConfigEnv: + options: dict[str, Any] + def __init__(self, **options: Any) -> None: ... + def update_config_options(self, **kwargs: Any) -> None: ... + def clear_config_options(self) -> None: ... + def get_config_options(self) -> dict[str, Any]: ... + +class GDALEnv(ConfigEnv): + def __init__(self, **options: Any) -> None: ... + def start(self) -> None: ... + def stop(self) -> None: ... + +class GDALDataFinder: + def find_file(self, basename: str) -> str | None: ... + def search(self, prefix: str | None = None) -> str | None: ... + def search_wheel(self, prefix: str | None = None) -> str | None: ... + def search_prefix(self, prefix: str) -> str | None: ... + def search_debian(self, prefix: str) -> str | None: ... + +class PROJDataFinder: + def has_data(self) -> bool: ... + def search(self, prefix: str | None = None) -> str | None: ... + def search_wheel(self, prefix: str | None = None) -> str | None: ... + def search_prefix(self, prefix: str) -> str | None: ... diff --git a/stubs/rasterio/rasterio/_err.pyi b/stubs/rasterio/rasterio/_err.pyi new file mode 100644 index 000000000000..e3606d30aabd --- /dev/null +++ b/stubs/rasterio/rasterio/_err.pyi @@ -0,0 +1,43 @@ +from contextlib import AbstractContextManager +from enum import IntEnum +from typing import Final + +class GDALError(IntEnum): + none = 0 + debug = 1 + warning = 2 + failure = 3 + fatal = 4 + +class CPLE_BaseError(Exception): + # Runtime instance attributes set in __init__ (modeled at class level + # to keep the stub static-type-friendly). + error: int + errno: int + errmsg: str + def __init__(self, error: int, errno: int, errmsg: str) -> None: ... + +class CPLE_AppDefinedError(CPLE_BaseError): ... +class CPLE_AssertionFailedError(CPLE_BaseError): ... +class CPLE_FileIOError(CPLE_BaseError): ... +class CPLE_HttpResponseError(CPLE_BaseError): ... +class CPLE_IllegalArgError(CPLE_BaseError): ... +class CPLE_NoWriteAccessError(CPLE_BaseError): ... +class CPLE_NotSupportedError(CPLE_BaseError): ... +class CPLE_OpenFailedError(CPLE_BaseError): ... +class CPLE_OutOfMemoryError(CPLE_BaseError): ... +class CPLE_UserInterruptError(CPLE_BaseError): ... +class CPLE_AWSAccessDeniedError(CPLE_BaseError): ... +class CPLE_AWSBucketNotFoundError(CPLE_BaseError): ... +class CPLE_AWSError(CPLE_BaseError): ... +class CPLE_AWSInvalidCredentialsError(CPLE_BaseError): ... +class CPLE_AWSObjectNotFoundError(CPLE_BaseError): ... +class CPLE_AWSSignatureDoesNotMatchError(CPLE_BaseError): ... +class ObjectNullError(CPLE_BaseError): ... + +exception_map: Final[dict[int, type[CPLE_BaseError]]] + +class StackChecker: + def __init__(self) -> None: ... + +def stack_errors() -> AbstractContextManager[StackChecker]: ... diff --git a/stubs/rasterio/rasterio/_features.pyi b/stubs/rasterio/rasterio/_features.pyi new file mode 100644 index 000000000000..990dd3f6c79d --- /dev/null +++ b/stubs/rasterio/rasterio/_features.pyi @@ -0,0 +1,30 @@ +from collections.abc import Iterator +from typing import Any, Final + +from rasterio.enums import MergeAlg as MergeAlg + +GEOMETRY_TYPES: Final[dict[int, str]] +GEOJSON2OGR_GEOMETRY_TYPES: Final[dict[str, int]] + +bool_: Final[str] +int8: Final[str] +int16: Final[str] +int32: Final[str] +int64: Final[str] +uint8: Final[str] +uint16: Final[str] +uint32: Final[str] +uint64: Final[str] +float16: Final[str] +float32: Final[str] +float64: Final[str] + +class GeomBuilder: + def build(self, geom: Any) -> dict[str, Any]: ... + +class OGRGeomBuilder: + def build(self, geom: dict[str, Any]) -> Any: ... + +class ShapeIterator: + def __iter__(self) -> Iterator[tuple[dict[str, Any], float]]: ... + def __next__(self) -> tuple[dict[str, Any], float]: ... diff --git a/stubs/rasterio/rasterio/_filepath.pyi b/stubs/rasterio/rasterio/_filepath.pyi new file mode 100644 index 000000000000..ea460c19d72c --- /dev/null +++ b/stubs/rasterio/rasterio/_filepath.pyi @@ -0,0 +1,6 @@ +from typing import Any + +class FilePathBase: + def __init__(self, *args: Any, **kwargs: Any) -> None: ... + +def clone_file_obj(fobj: Any) -> Any: ... diff --git a/stubs/rasterio/rasterio/_io.pyi b/stubs/rasterio/rasterio/_io.pyi new file mode 100644 index 000000000000..47ebe0805a89 --- /dev/null +++ b/stubs/rasterio/rasterio/_io.pyi @@ -0,0 +1,212 @@ +import os +from collections.abc import Iterator, Sequence +from typing import Any, BinaryIO, Final, Self +from typing_extensions import deprecated + +from numpy.typing import DTypeLike, NDArray +from rasterio._affine_types import Affine +from rasterio._base import DatasetBase +from rasterio._path import _ParsedPath, _UnparsedPath +from rasterio._typing import Colormap, CRSInput, Indexes, NumType, ShapeND, WindowInput +from rasterio.control import GroundControlPoint +from rasterio.enums import Resampling +from rasterio.rpc import RPC + +def validate_resampling(resampling: Resampling) -> None: ... +def virtual_file_to_buffer(filename: str) -> bytes: ... + +# `_gdal_typename`, `_get_gdal_dtype`, and `_is_complex_int` are Cython +# re-imports from `rasterio.dtypes`; declared here for stub-only callers +# that import them from `rasterio._io`. +def _is_complex_int(dtype: Any) -> bool: ... +def _getnpdtype(dtype: Any) -> Any: ... +def _gdal_typename(dt: Any) -> str: ... +def _get_gdal_dtype(type_name: Any) -> int: ... +def _boundless_vrt_doc( + src_dataset: DatasetBase, + nodata: float | None = None, + background: float | None = None, + hidenodata: bool = False, + width: int | None = None, + height: int | None = None, + transform: Affine | None = None, + masked: bool = False, + resampling: Resampling = ..., +) -> str: ... +def sample_gen( + dataset: DatasetBase, + xy: Sequence[tuple[float, float]], + indexes: Indexes | None = None, + masked: bool = False, +) -> Iterator[NDArray[Any]]: ... + +class Statistics: + min: float + max: float + mean: float + std: float + def __init__(self, min: float, max: float, mean: float, std: float) -> None: ... + +class DatasetReaderBase(DatasetBase): + def read( + self, + indexes: Indexes | None = None, + out: NDArray[Any] | None = None, + window: WindowInput | None = None, + masked: bool = False, + out_shape: ShapeND | None = None, + boundless: bool = False, + resampling: Resampling = ..., + fill_value: NumType | None = None, + out_dtype: DTypeLike | None = None, + ) -> NDArray[Any]: ... + def read_masks( + self, + indexes: Indexes | None = None, + out: NDArray[Any] | None = None, + out_shape: ShapeND | None = None, + window: WindowInput | None = None, + boundless: bool = False, + resampling: Resampling = ..., + ) -> NDArray[Any]: ... + def dataset_mask( + self, + out: NDArray[Any] | None = None, + out_shape: ShapeND | None = None, + window: WindowInput | None = None, + boundless: bool = False, + resampling: Resampling = ..., + ) -> NDArray[Any]: ... + def sample( + self, + xy: Sequence[tuple[float, float]], + indexes: Indexes | None = None, + masked: bool = False, + ) -> Iterator[NDArray[Any]]: ... + def stats(self, *, indexes: Indexes | None = None, approx: bool = False) -> list[Statistics]: ... + @deprecated("DatasetReaderBase.statistics() will be removed in 2.0.0; please switch to stats().") + def statistics(self, bidx: int, approx: bool = False, clear_cache: bool = False) -> Statistics: ... + +class MemoryFileBase: + name: str + mode: str + closed: bool + def __init__( + self, + file_or_bytes: bytes | BinaryIO | None = None, + dirname: str | None = None, + filename: str | None = None, + ext: str = "", + ) -> None: ... + def __len__(self) -> int: ... + def exists(self) -> bool: ... + def getbuffer(self) -> memoryview: ... + def close(self) -> None: ... + def seek(self, offset: int, whence: int = 0) -> int: ... + def tell(self) -> int: ... + def read(self, size: int = -1) -> bytes: ... + def write(self, data: bytes) -> int: ... + +class DatasetWriterBase(DatasetReaderBase): + name: str + mode: str + width: int + height: int + shape: tuple[int, int] + driver: str + + def __init__( + self, + path: str | os.PathLike[str] | _ParsedPath | _UnparsedPath, + mode: str, + driver: str | None = None, + width: int | None = None, + height: int | None = None, + count: int | None = None, + crs: CRSInput | None = None, + transform: Affine | None = None, + dtype: DTypeLike | None = None, + nodata: float | None = None, + gcps: Sequence[GroundControlPoint] | None = None, + rpcs: RPC | None = None, + sharing: bool = False, + **kwargs: Any, + ) -> None: ... + def write( + self, + arr: NDArray[Any], + indexes: Indexes | None = None, + window: WindowInput | None = None, + masked: bool = False, + ) -> None: ... + def write_band( + self, + bidx: int, + src: NDArray[Any], + window: WindowInput | None = None, + ) -> None: ... + def update_tags( + self, + bidx: int = 0, + ns: str | None = None, + **kwargs: Any, + ) -> None: ... + def set_band_description(self, bidx: int, value: str) -> None: ... + def set_band_unit(self, bidx: int, value: str) -> None: ... + def write_colormap(self, bidx: int, colormap: Colormap) -> None: ... + def write_mask( + self, + mask_array: NDArray[Any], + window: WindowInput | None = None, + ) -> None: ... + def build_overviews( + self, + factors: Sequence[int], + resampling: Resampling = ..., + ) -> None: ... + def update_stats( + self, + *, + stats: Sequence[Statistics] | None = None, + indexes: Indexes | None = None, + approx: bool = False, + ) -> None: ... + def clear_stats(self) -> None: ... + +class MemoryDataset(DatasetWriterBase): + def __init__( + self, + image: NDArray[Any] | None = None, + dtype: DTypeLike | None = None, + count: int = 1, + width: int | None = None, + height: int | None = None, + transform: Affine | None = None, + gcps: Sequence[GroundControlPoint] | None = None, + rpcs: RPC | None = None, + crs: CRSInput | None = None, + ) -> None: ... + def __enter__(self) -> Self: ... + +class BufferedDatasetWriterBase(DatasetWriterBase): + def __init__( + self, + path: str | os.PathLike[str] | _ParsedPath | _UnparsedPath, + mode: str = "w", + driver: str | None = None, + width: int | None = None, + height: int | None = None, + count: int | None = None, + crs: CRSInput | None = None, + transform: Affine | None = None, + dtype: DTypeLike | None = None, + nodata: float | None = None, + gcps: Sequence[GroundControlPoint] | None = None, + rpcs: RPC | None = None, + sharing: bool = False, + **kwargs: Any, + ) -> None: ... + def stop(self) -> None: ... + +int8: Final[str] +uint8: Final[str] diff --git a/stubs/rasterio/rasterio/_path.pyi b/stubs/rasterio/rasterio/_path.pyi new file mode 100644 index 000000000000..c4f4ac18507c --- /dev/null +++ b/stubs/rasterio/rasterio/_path.pyi @@ -0,0 +1,35 @@ +import os +from typing import Any, Final, Self + +SCHEMES: Final[dict[str, str]] +# In rasterio 1.5 the source assigns `ARCHIVESCHEMES = set` (the bare type), +# not a populated set instance. We mirror that quirk. +ARCHIVESCHEMES: Final[type[set[Any]]] +CURLSCHEMES: Final[set[str]] +REMOTESCHEMES: Final[set[str]] + +class _Path: + def as_vsi(self) -> str: ... + +class _ParsedPath(_Path): + path: str + archive: str | None + scheme: str | None + def __init__(self, path: str, archive: str | None, scheme: str | None) -> None: ... + @classmethod + def from_uri(cls, uri: str) -> Self: ... + @property + def name(self) -> str: ... + @property + def is_remote(self) -> bool: ... + @property + def is_local(self) -> bool: ... + +class _UnparsedPath(_Path): + path: str + def __init__(self, path: str) -> None: ... + @property + def name(self) -> str: ... + +def _parse_path(path: str | os.PathLike[str] | _Path) -> _ParsedPath | _UnparsedPath: ... +def _vsi_path(path: _Path) -> str: ... diff --git a/stubs/rasterio/rasterio/_show_versions.pyi b/stubs/rasterio/rasterio/_show_versions.pyi new file mode 100644 index 000000000000..1eeec0747405 --- /dev/null +++ b/stubs/rasterio/rasterio/_show_versions.pyi @@ -0,0 +1 @@ +def show_versions() -> None: ... diff --git a/stubs/rasterio/rasterio/_transform.pyi b/stubs/rasterio/rasterio/_transform.pyi new file mode 100644 index 000000000000..28a1a0bfc98f --- /dev/null +++ b/stubs/rasterio/rasterio/_transform.pyi @@ -0,0 +1,16 @@ +from collections.abc import Sequence +from typing import Any + +from rasterio.control import GroundControlPoint +from rasterio.errors import TransformWarning as TransformWarning +from rasterio.rpc import RPC + +class GCPTransformerBase: + def __init__(self, gcps: Sequence[GroundControlPoint]) -> None: ... + def close(self) -> None: ... + +class RPCTransformerBase: + def __init__(self, rpcs: RPC, **kwargs: Any) -> None: ... + def close(self) -> None: ... + +def _transform_from_gcps(gcps: Sequence[GroundControlPoint]) -> tuple[float, ...]: ... diff --git a/stubs/rasterio/rasterio/_typing.pyi b/stubs/rasterio/rasterio/_typing.pyi new file mode 100644 index 000000000000..5026e284cb3b --- /dev/null +++ b/stubs/rasterio/rasterio/_typing.pyi @@ -0,0 +1,15 @@ +from collections.abc import Sequence +from typing import BinaryIO, TypeAlias + +from rasterio.crs import CRS +from rasterio.io import BufferedDatasetWriter, DatasetReader, DatasetWriter, MemoryFile +from rasterio.windows import Window + +AnyDataset: TypeAlias = DatasetReader | DatasetWriter | BufferedDatasetWriter | MemoryFile +Colormap: TypeAlias = dict[int, tuple[int, int, int] | tuple[int, int, int, int]] +CRSInput: TypeAlias = str | dict[str, str] | CRS +FileOrBytes: TypeAlias = BinaryIO | bytes +Indexes: TypeAlias = int | Sequence[int] +NumType: TypeAlias = int | float +ShapeND: TypeAlias = Sequence[int] +WindowInput: TypeAlias = Window | tuple[tuple[int, int], tuple[int, int]] diff --git a/stubs/rasterio/rasterio/_version.pyi b/stubs/rasterio/rasterio/_version.pyi new file mode 100644 index 000000000000..063e03ad00dd --- /dev/null +++ b/stubs/rasterio/rasterio/_version.pyi @@ -0,0 +1,5 @@ +def gdal_version() -> str: ... +def get_gdal_version_info(key: str) -> str: ... +def check_gdal_version(major: int, minor: int) -> bool: ... +def get_geos_version() -> tuple[int, int, int]: ... +def get_proj_version() -> tuple[int, int, int]: ... diff --git a/stubs/rasterio/rasterio/_vsiopener.pyi b/stubs/rasterio/rasterio/_vsiopener.pyi new file mode 100644 index 000000000000..19d4d62489ea --- /dev/null +++ b/stubs/rasterio/rasterio/_vsiopener.pyi @@ -0,0 +1,20 @@ +from abc import ABC, abstractmethod +from contextlib import AbstractContextManager +from typing import Any, BinaryIO + +from rasterio.errors import OpenerRegistrationError as OpenerRegistrationError + +class FileContainer(ABC): + @abstractmethod + def open(self, path: str, mode: str = "r", **kwds: Any) -> BinaryIO: ... + +class MultiByteRangeResource(ABC): + @abstractmethod + def get_byte_ranges(self, offsets: list[int], sizes: list[int]) -> list[bytes]: ... + +class MultiByteRangeResourceContainer(FileContainer): + @abstractmethod + def open(self, path: str, **kwds: Any) -> MultiByteRangeResource: ... # type: ignore[override] + +def to_pyopener(obj: Any) -> FileContainer: ... +def _opener_registration(urlpath: str, obj: Any) -> AbstractContextManager[str]: ... diff --git a/stubs/rasterio/rasterio/_warp.pyi b/stubs/rasterio/rasterio/_warp.pyi new file mode 100644 index 000000000000..11f355dd933a --- /dev/null +++ b/stubs/rasterio/rasterio/_warp.pyi @@ -0,0 +1,135 @@ +from collections.abc import Mapping, Sequence +from typing import Any, Final + +from numpy.typing import DTypeLike, NDArray +from rasterio._affine_types import Affine +from rasterio._io import DatasetReaderBase +from rasterio._typing import CRSInput, Indexes, ShapeND, WindowInput +from rasterio.control import GroundControlPoint +from rasterio.crs import CRS +from rasterio.enums import Resampling +from rasterio.io import DatasetReader +from rasterio.rpc import RPC + +SUPPORTED_RESAMPLING: Final[list[Resampling]] +DEFAULT_NODATA_FLAG: Final[object] + +def recursive_round(val: Any, precision: int) -> Any: ... +def _transform_geom( + src_crs: CRSInput, + dst_crs: CRSInput, + geom: Mapping[str, Any] | Sequence[Mapping[str, Any]], + precision: int, +) -> dict[str, Any] | list[dict[str, Any]]: ... +def _reproject( + source: NDArray[Any] | Any, + destination: NDArray[Any] | Any, + src_transform: Affine | None = None, + gcps: Sequence[GroundControlPoint] | None = None, + rpcs: RPC | None = None, + src_crs: CRSInput | None = None, + src_nodata: float | None = None, + dst_transform: Affine | None = None, + dst_crs: CRSInput | None = None, + dst_nodata: float | None = None, + dst_alpha: int = 0, + src_alpha: int = 0, + resampling: Resampling = ..., + init_dest_nodata: bool = True, + tolerance: float = 0.125, + num_threads: int = 1, + warp_mem_limit: int = 0, + working_data_type: int = 0, + src_geoloc_array: NDArray[Any] | None = None, + **kwargs: Any, +) -> tuple[NDArray[Any], Affine]: ... +def _calculate_default_transform( + src_crs: CRSInput, + dst_crs: CRSInput, + width: int, + height: int, + left: float | None = None, + bottom: float | None = None, + right: float | None = None, + top: float | None = None, + gcps: Sequence[GroundControlPoint] | None = None, + rpcs: RPC | None = None, + src_geoloc_array: NDArray[Any] | None = None, + **kwargs: Any, +) -> tuple[Affine, int, int]: ... +def _transform_bounds( + src_crs: CRS, + dst_crs: CRS, + left: float, + bottom: float, + right: float, + top: float, + densify_pts: int, +) -> tuple[float, float, float, float]: ... +def _suggested_proxy_vrt_doc( + width: int, + height: int, + transform: Affine | None = None, + crs: CRSInput | None = None, + gcps: Sequence[GroundControlPoint] | None = None, + rpcs: RPC | None = None, +) -> str: ... + +class WarpedVRTReaderBase(DatasetReaderBase): + # Public attributes documented in the rasterio.vrt API reference and set + # in __init__. + src_dataset: DatasetReader + src_crs: CRS + src_transform: Affine | None + resampling: Resampling + tolerance: float + src_nodata: float | None + dst_nodata: float | None + working_dtype: DTypeLike | None + warp_extras: dict[str, Any] + + def __init__( + self, + src_dataset: DatasetReader, + src_crs: CRSInput | None = None, + crs: CRSInput | None = None, + resampling: Resampling = ..., + tolerance: float = 0.125, + src_nodata: float | None = ..., + nodata: float | None = ..., + width: int | None = None, + height: int | None = None, + src_transform: Affine | None = None, + transform: Affine | None = None, + init_dest_nodata: bool = True, + src_alpha: int = 0, + dst_alpha: int = 0, + add_alpha: bool = False, + warp_mem_limit: int = 0, + dtype: DTypeLike | None = None, + **warp_extras: Any, + ) -> None: ... + # The base read() takes `boundless`; WarpedVRT.read() does not. The base + # read() takes a generic out_shape; the WarpedVRT version reorders kwargs. + # These divergences are intentional in rasterio's API. + def read( # type: ignore[override] + self, + indexes: Indexes | None = None, + out: NDArray[Any] | None = None, + window: WindowInput | None = None, + masked: bool = False, + out_shape: ShapeND | None = None, + resampling: Resampling = ..., + fill_value: float | None = None, + out_dtype: DTypeLike | None = None, + **kwargs: Any, + ) -> NDArray[Any]: ... + def read_masks( # type: ignore[override] + self, + indexes: Indexes | None = None, + out: NDArray[Any] | None = None, + out_shape: ShapeND | None = None, + window: WindowInput | None = None, + resampling: Resampling = ..., + **kwargs: Any, + ) -> NDArray[Any]: ... diff --git a/stubs/rasterio/rasterio/abc.pyi b/stubs/rasterio/rasterio/abc.pyi new file mode 100644 index 000000000000..d9ebb71719e0 --- /dev/null +++ b/stubs/rasterio/rasterio/abc.pyi @@ -0,0 +1 @@ +from rasterio._vsiopener import FileContainer as FileContainer, MultiByteRangeResourceContainer as MultiByteRangeResourceContainer diff --git a/stubs/rasterio/rasterio/cache.pyi b/stubs/rasterio/rasterio/cache.pyi new file mode 100644 index 000000000000..ab1f8b285843 --- /dev/null +++ b/stubs/rasterio/rasterio/cache.pyi @@ -0,0 +1,2 @@ +def invalidate(pattern: str) -> None: ... +def invalidate_all() -> None: ... diff --git a/stubs/rasterio/rasterio/control.pyi b/stubs/rasterio/rasterio/control.pyi new file mode 100644 index 000000000000..0fbec047e6be --- /dev/null +++ b/stubs/rasterio/rasterio/control.pyi @@ -0,0 +1,46 @@ +from collections.abc import Sequence +from typing import Literal, TypedDict, type_check_only + +@type_check_only +class GroundControlPointDict(TypedDict): + id: str + info: str | None + row: float + col: float + x: float + y: float + z: float | None + +@type_check_only +class GroundControlPointGeometry(TypedDict): + type: Literal["Point"] + coordinates: Sequence[float] + +@type_check_only +class GroundControlPointFeature(TypedDict): + id: str + type: Literal["Feature"] + geometry: GroundControlPointGeometry + properties: GroundControlPointDict + +class GroundControlPoint: + id: str + info: str | None + row: float + col: float + x: float + y: float + z: float | None + def __init__( + self, + row: float | None = None, + col: float | None = None, + x: float | None = None, + y: float | None = None, + z: float | None = None, + id: str | None = None, + info: str | None = None, + ) -> None: ... + def asdict(self) -> GroundControlPointDict: ... + @property + def __geo_interface__(self) -> GroundControlPointFeature: ... diff --git a/stubs/rasterio/rasterio/coords.pyi b/stubs/rasterio/rasterio/coords.pyi new file mode 100644 index 000000000000..c7b97fc2fe31 --- /dev/null +++ b/stubs/rasterio/rasterio/coords.pyi @@ -0,0 +1,11 @@ +from typing import NamedTuple, TypeAlias + +_Quadruple: TypeAlias = tuple[float, float, float, float] + +class BoundingBox(NamedTuple): + left: float + bottom: float + right: float + top: float + +def disjoint_bounds(bounds1: BoundingBox | _Quadruple, bounds2: BoundingBox | _Quadruple) -> bool: ... diff --git a/stubs/rasterio/rasterio/crs.pyi b/stubs/rasterio/rasterio/crs.pyi new file mode 100644 index 000000000000..1b166afb54c2 --- /dev/null +++ b/stubs/rasterio/rasterio/crs.pyi @@ -0,0 +1,79 @@ +from collections.abc import Iterator, Mapping +from typing import Any, Self +from typing_extensions import deprecated, disjoint_base + +from rasterio.enums import WktVersion + +# Set of recognised PROJ parameter keys (e.g. "x_0", "lat_0", "proj"). +# Used by CRS.to_string to strip unknown keys; documented and inspectable. +all_proj_keys: set[str] + +@disjoint_base +class CRS(Mapping[str, Any]): + def __init__(self, initialdata: Mapping[str, Any] | None = None, **kwargs: Any) -> None: ... + def __getitem__(self, key: str, /) -> Any: ... + def __iter__(self) -> Iterator[str]: ... + def __len__(self) -> int: ... + def __bool__(self) -> bool: ... + def __nonzero__(self) -> bool: ... + def __eq__(self, other: object, /) -> bool: ... + def __copy__(self) -> Self: ... + def __hash__(self) -> int: ... + def __getstate__(self) -> dict[str, Any]: ... + def __setstate__(self, state: Mapping[str, Any]) -> None: ... + def to_proj4(self) -> str: ... + def to_wkt( + self, + morph_to_esri_dialect: bool = False, + version: WktVersion | str | None = None, + ) -> str: ... + @property + def wkt(self) -> str: ... + def to_epsg(self, confidence_threshold: int = 70) -> int | None: ... + def to_authority(self, confidence_threshold: int = 70) -> tuple[str, str] | None: ... + def to_dict(self, projjson: bool = False) -> dict[str, Any]: ... + @property + def data(self) -> dict[str, Any]: ... + @property + def is_geographic(self) -> bool: ... + @property + def is_projected(self) -> bool: ... + @property + @deprecated("CRS.is_valid is deprecated since rasterio 1.4 and will be removed in 2.0.0.") + def is_valid(self) -> bool: ... + @property + def is_epsg_code(self) -> bool: ... + @property + def linear_units_factor(self) -> tuple[str, float]: ... + @property + def linear_units(self) -> str: ... + @property + def units_factor(self) -> tuple[str, float]: ... + # New in rasterio 1.5: lazily-computed geodetic CRS. + @property + def geodetic_crs(self) -> CRS | None: ... + def to_string(self) -> str: ... + # In rasterio 1.5 these are bound as a static method that gets `cls` + # passed at runtime via Cython; stubtest sees them as staticmethods. + def equals(self, other: CRS, ignore_axis_order: bool = False) -> bool: ... + # CRS.get drops Mapping.get's default-value parameter at runtime; this is + # a deliberate divergence from the Mapping protocol. + def get(self, item: str) -> Any: ... # type: ignore[override] + @staticmethod + def from_epsg(code: int | str) -> CRS: ... + @staticmethod + def from_authority(auth_name: str, code: int | str) -> CRS: ... + @staticmethod + def from_string(value: str, morph_from_esri_dialect: bool = False) -> CRS: ... + @staticmethod + def from_proj4(proj: str) -> CRS: ... + @staticmethod + def from_dict(initialdata: Mapping[str, Any] | None = None, **kwargs: Any) -> CRS: ... + @staticmethod + def from_wkt(wkt: str, morph_from_esri_dialect: bool = False) -> CRS: ... + @staticmethod + def from_user_input(value: Any, morph_from_esri_dialect: bool = False) -> CRS: ... + +def epsg_treats_as_latlong(input_crs: CRS) -> bool: ... +def epsg_treats_as_northingeasting(input_crs: CRS) -> bool: ... +def auth_preference(item: str) -> None: ... diff --git a/stubs/rasterio/rasterio/drivers.pyi b/stubs/rasterio/rasterio/drivers.pyi new file mode 100644 index 000000000000..96b6d727bd5b --- /dev/null +++ b/stubs/rasterio/rasterio/drivers.pyi @@ -0,0 +1,8 @@ +import os +from typing import Final + +blacklist: Final[dict[str, tuple[str, ...]]] + +def raster_driver_extensions() -> dict[str, str]: ... +def driver_from_extension(path: str | os.PathLike[str]) -> str: ... +def is_blacklisted(name: str, mode: str) -> bool: ... diff --git a/stubs/rasterio/rasterio/dtypes.pyi b/stubs/rasterio/rasterio/dtypes.pyi new file mode 100644 index 000000000000..99e2299ea733 --- /dev/null +++ b/stubs/rasterio/rasterio/dtypes.pyi @@ -0,0 +1,40 @@ +from collections.abc import Sequence +from typing import Any, Final + +from numpy.typing import ArrayLike, DTypeLike + +bool_: Final[str] +ubyte: Final[str] +uint8: Final[str] +sbyte: Final[str] +int8: Final[str] +uint16: Final[str] +int16: Final[str] +uint32: Final[str] +int32: Final[str] +int64: Final[str] +uint64: Final[str] +# New in rasterio 1.5 (requires GDAL 3.10+). +float16: Final[str] +float32: Final[str] +float64: Final[str] +complex_: Final[str] +complex64: Final[str] +complex128: Final[str] +complex_int16: Final[str] + +dtype_fwd: Final[dict[int, str | None]] +dtype_rev: Final[dict[str | None, int]] +typename_fwd: Final[dict[int, str]] +typename_rev: Final[dict[str, int]] +dtype_ranges: Final[dict[str, tuple[float, float]]] +# Dispatch table from rasterio dtype letter codes to numpy info classes +# (`numpy.iinfo` / `numpy.finfo`). Used internally by `in_dtype_range`. +dtype_info_registry: Final[dict[str, type]] + +def in_dtype_range(value: float, dtype: DTypeLike) -> bool: ... +def check_dtype(dt: DTypeLike) -> bool: ... +def get_minimum_dtype(values: ArrayLike) -> str: ... +def is_ndarray(array: Any) -> bool: ... +def can_cast_dtype(values: ArrayLike, dtype: DTypeLike) -> bool: ... +def validate_dtype(values: ArrayLike, valid_dtypes: Sequence[DTypeLike]) -> bool: ... diff --git a/stubs/rasterio/rasterio/enums.pyi b/stubs/rasterio/rasterio/enums.pyi new file mode 100644 index 000000000000..d23fd08f7ec7 --- /dev/null +++ b/stubs/rasterio/rasterio/enums.pyi @@ -0,0 +1,128 @@ +from enum import Enum, IntEnum + +class TransformDirection(IntEnum): + forward = 1 + reverse = 0 + +class TransformMethod(Enum): + affine = "transform" + gcps = "gcps" + rpcs = "rpcs" + +class ColorInterp(IntEnum): + undefined = 0 + gray = 1 + grey = 1 + palette = 2 + red = 3 + green = 4 + blue = 5 + alpha = 6 + hue = 7 + saturation = 8 + lightness = 9 + cyan = 10 + magenta = 11 + yellow = 12 + black = 13 + Y = 14 + Cb = 15 + Cr = 16 + # Below values require GDAL 3.10+ + pan = 17 + coastal = 18 + rededge = 19 + nir = 20 + swir = 21 + mwir = 22 + lwir = 23 + tir = 24 + other_ir = 25 + sar_ka = 30 + sar_k = 31 + sar_ku = 32 + sar_x = 33 + sar_c = 34 + sar_s = 35 + sar_l = 36 + sar_p = 37 + +class Resampling(IntEnum): + nearest = 0 + bilinear = 1 + cubic = 2 + cubic_spline = 3 + lanczos = 4 + average = 5 + mode = 6 + gauss = 7 + max = 8 + min = 9 + med = 10 + q1 = 11 + q3 = 12 + sum = 13 + rms = 14 + +class OverviewResampling(IntEnum): + nearest = 0 + bilinear = 1 + cubic = 2 + cubic_spline = 3 + lanczos = 4 + average = 5 + mode = 6 + gauss = 7 + rms = 14 + +class Compression(Enum): + jpeg = "JPEG" + lzw = "LZW" + packbits = "PACKBITS" + deflate = "DEFLATE" + ccittrle = "CCITTRLE" + ccittfax3 = "CCITTFAX3" + ccittfax4 = "CCITTFAX4" + lzma = "LZMA" + none = "NONE" + zstd = "ZSTD" + lerc = "LERC" + lerc_deflate = "LERC_DEFLATE" + lerc_zstd = "LERC_ZSTD" + webp = "WEBP" + jpeg2000 = "JPEG2000" + +class Interleaving(Enum): + pixel = "PIXEL" + line = "LINE" + band = "BAND" + # tile requires GDAL 3.11+ (new in rasterio 1.5) + tile = "TILE" + +class MaskFlags(IntEnum): + all_valid = 1 + per_dataset = 2 + alpha = 4 + nodata = 8 + +class PhotometricInterp(Enum): + black = "MINISBLACK" + white = "MINISWHITE" + rgb = "RGB" + cmyk = "CMYK" + ycbcr = "YCbCr" + cielab = "CIELAB" + icclab = "ICCLAB" + itulab = "ITULAB" + +class MergeAlg(Enum): + replace = "REPLACE" + add = "ADD" + +class WktVersion(Enum): + WKT2_2015 = "WKT2_2015" + WKT2 = "WKT2" + WKT2_2019 = "WKT2_2018" + WKT1_GDAL = "WKT1_GDAL" + WKT1 = "WKT1" + WKT1_ESRI = "WKT1_ESRI" diff --git a/stubs/rasterio/rasterio/env.pyi b/stubs/rasterio/rasterio/env.pyi new file mode 100644 index 000000000000..c98811e3f0ba --- /dev/null +++ b/stubs/rasterio/rasterio/env.pyi @@ -0,0 +1,100 @@ +import logging +import threading +from collections.abc import Callable, Iterable +from types import TracebackType +from typing import Any, Final, Self, TypeVar +from typing_extensions import deprecated + +from rasterio._env import ( + GDALDataFinder as GDALDataFinder, + GDALEnv as GDALEnv, + PROJDataFinder as PROJDataFinder, + get_gdal_config as get_gdal_config, + set_gdal_config as set_gdal_config, + set_proj_data_search_path as set_proj_data_search_path, +) +from rasterio.errors import ( + EnvError as EnvError, + GDALVersionError as GDALVersionError, + RasterioDeprecationWarning as RasterioDeprecationWarning, +) +from rasterio.session import DummySession as DummySession, Session as Session + +_F = TypeVar("_F", bound=Callable[..., Any]) + +class ThreadEnv(threading.local): + def __init__(self) -> None: ... + +local: ThreadEnv +log: logging.Logger + +class Env: + session: Session + options: dict[str, Any] + context_options: dict[str, Any] + def __init__( + self, + session: Session | None = None, + aws_unsigned: bool = False, + profile_name: str | None = None, + # Defaults to Session.aws_or_dummy at runtime, but any + # Session-returning callable works. + session_class: Callable[..., Session] = ..., + **options: Any, + ) -> None: ... + @classmethod + def default_options(cls) -> dict[str, Any]: ... + @classmethod + def from_defaults(cls, *args: Any, **kwargs: Any) -> Self: ... + def credentialize(self) -> None: ... + def drivers(self) -> dict[str, str]: ... + def __enter__(self) -> Self: ... + def __exit__( + self, + exc_type: type[BaseException] | None = None, + exc_val: BaseException | None = None, + exc_tb: TracebackType | None = None, + ) -> None: ... + +def defenv(**options: Any) -> None: ... +def getenv() -> dict[str, Any]: ... +def hasenv() -> bool: ... +def setenv(**options: Any) -> None: ... +@deprecated("Please use Env.session.hascreds() instead.") +def hascreds() -> bool: ... +def delenv() -> None: ... + +class NullContextManager: + def __init__(self) -> None: ... + def __enter__(self) -> Self: ... + def __exit__(self, *args: object) -> None: ... + +def env_ctx_if_needed() -> Env | NullContextManager: ... +def ensure_env(f: _F) -> _F: ... +@deprecated("ensure_env_credentialled is a deprecated alias; use ensure_env_with_credentials instead.") +def ensure_env_credentialled(f: _F) -> _F: ... +def ensure_env_with_credentials(f: _F) -> _F: ... +def gdal_version() -> str: ... + +class GDALVersion: + major: int + minor: int + patch: int + def __init__(self, major: int = 0, minor: int = 0, patch: int = 0) -> None: ... + def __eq__(self, other: object) -> bool: ... + def __lt__(self, other: GDALVersion) -> bool: ... + @classmethod + def parse(cls, input: str | GDALVersion, include_patch: bool = False) -> Self: ... + @classmethod + def runtime(cls, include_patch: bool = False) -> Self: ... + def at_least(self, other: str | GDALVersion, include_patch: bool = False) -> bool: ... + +def require_gdal_version( + version: str | GDALVersion, + param: str | None = None, + values: Iterable[Any] | None = None, + is_max_version: bool = False, + reason: str = "", +) -> Callable[[_F], _F]: ... + +path: Final[str | None] diff --git a/stubs/rasterio/rasterio/errors.pyi b/stubs/rasterio/rasterio/errors.pyi new file mode 100644 index 000000000000..c883864c3f86 --- /dev/null +++ b/stubs/rasterio/rasterio/errors.pyi @@ -0,0 +1,40 @@ +from click import FileError + +class RasterioError(Exception): ... +class InvalidArrayError(RasterioError): ... +class WindowError(RasterioError): ... +class CRSError(ValueError): ... +class EnvError(RasterioError): ... +class DriverCapabilityError(RasterioError, ValueError): ... +class DriverRegistrationError(ValueError): ... + +class FileOverwriteError(FileError): + def __init__(self, message: str) -> None: ... + +class RasterioIOError(RasterioError, OSError): ... +class NodataShadowWarning(UserWarning): ... +class NotGeoreferencedWarning(UserWarning): ... +class TransformWarning(UserWarning): ... +class RPCError(ValueError): ... +class ShapeSkipWarning(UserWarning): ... +class GDALBehaviorChangeException(RuntimeError): ... +class GDALOptionNotImplementedError(RasterioError): ... +class GDALVersionError(RasterioError): ... +class WindowEvaluationError(ValueError): ... +class RasterioDeprecationWarning(FutureWarning): ... +class RasterBlockError(RasterioError): ... +class BandOverviewError(UserWarning): ... +class WarpOptionsError(RasterioError): ... +class UnsupportedOperation(RasterioError): ... +class OverviewCreationError(RasterioError): ... +class DatasetAttributeError(RasterioError, NotImplementedError): ... +class PathError(RasterioError): ... +class ResamplingAlgorithmError(RasterioError): ... +class TransformError(RasterioError): ... +class WarpedVRTError(RasterioError): ... +class DatasetIOShapeError(RasterioError): ... +class WarpOperationError(RasterioError): ... +class StatisticsError(RasterioError): ... +class OpenerRegistrationError(RasterioError): ... +class MergeError(RasterioError): ... +class StackError(RasterioError): ... diff --git a/stubs/rasterio/rasterio/features.pyi b/stubs/rasterio/rasterio/features.pyi new file mode 100644 index 000000000000..2eab145af009 --- /dev/null +++ b/stubs/rasterio/rasterio/features.pyi @@ -0,0 +1,91 @@ +import os +from collections.abc import Iterable, Iterator, Mapping +from typing import Any, TypeAlias, overload +from typing_extensions import deprecated + +import numpy as np +from numpy.typing import DTypeLike, NDArray +from rasterio._affine_types import Affine +from rasterio.enums import MergeAlg as MergeAlg +from rasterio.io import DatasetReader +from rasterio.windows import Window as Window + +# Stubs-only type alias for GeoJSON-like dicts. Not exported at runtime. +Geometry: TypeAlias = Mapping[str, Any] + +def geometry_mask( + geometries: Iterable[Geometry], + out_shape: tuple[int, int], + transform: Affine, + all_touched: bool = False, + invert: bool = False, +) -> NDArray[np.bool_]: ... +def shapes( + source: NDArray[Any], + mask: NDArray[np.bool_] | None = None, + connectivity: int = 4, + transform: Affine = ..., +) -> Iterator[tuple[dict[str, Any], float | int]]: ... +def sieve( + source: NDArray[Any], + size: int, + out: NDArray[Any] | None = None, + mask: NDArray[np.bool_] | None = None, + connectivity: int = 4, +) -> NDArray[Any]: ... +def rasterize( + shapes: Iterable[tuple[Geometry, float] | Geometry], + out_shape: tuple[int, int] | None = None, + fill: float = 0, + nodata: float | None = None, + masked: bool = False, + out: NDArray[Any] | None = None, + transform: Affine = ..., + all_touched: bool = False, + merge_alg: MergeAlg = ..., + default_value: float = 1, + dtype: DTypeLike | None = None, + skip_invalid: bool = True, + dst_path: str | os.PathLike[str] | None = None, + dst_kwds: dict[str, Any] | None = None, +) -> NDArray[Any]: ... +def bounds( + geometry: Geometry, + north_up: bool = True, + transform: Affine | None = None, +) -> tuple[float, float, float, float]: ... +@overload +def geometry_window( + dataset: DatasetReader, + shapes: Iterable[Geometry], + pad_x: float = 0, + pad_y: float = 0, + *, + boundless: bool = False, +) -> Window: ... +@overload +@deprecated( + "`north_up`, `rotated`, and `pixel_precision` on features.geometry_window are " + "unused since rasterio 1.2.1 and will be removed in a future release." +) +def geometry_window( + dataset: DatasetReader, + shapes: Iterable[Geometry], + pad_x: float = 0, + pad_y: float = 0, + north_up: bool | None = None, + rotated: bool | None = None, + pixel_precision: float | None = None, + boundless: bool = False, +) -> Window: ... +def is_valid_geom(geom: Geometry) -> bool: ... +def dataset_features( + src: DatasetReader, + bidx: int | None = None, + sampling: int = 1, + band: bool = True, + as_mask: bool = False, + with_nodata: bool = False, + geographic: bool = True, + precision: int = -1, +) -> Iterator[dict[str, Any]]: ... diff --git a/stubs/rasterio/rasterio/fill.pyi b/stubs/rasterio/rasterio/fill.pyi new file mode 100644 index 000000000000..8f121f75a3a8 --- /dev/null +++ b/stubs/rasterio/rasterio/fill.pyi @@ -0,0 +1,11 @@ +from typing import Any + +from numpy.ma import MaskedArray +from numpy.typing import NDArray + +def fillnodata( + image: NDArray[Any] | MaskedArray[Any, Any], + mask: NDArray[Any] | None = None, + max_search_distance: float = 100.0, + smoothing_iterations: int = 0, +) -> NDArray[Any]: ... diff --git a/stubs/rasterio/rasterio/io.pyi b/stubs/rasterio/rasterio/io.pyi new file mode 100644 index 000000000000..51da8bf40bfc --- /dev/null +++ b/stubs/rasterio/rasterio/io.pyi @@ -0,0 +1,93 @@ +from types import TracebackType +from typing import Any, Self +from typing_extensions import deprecated + +from numpy.typing import DTypeLike +from rasterio._affine_types import Affine +from rasterio._filepath import FilePathBase as FilePathBase +from rasterio._io import ( + BufferedDatasetWriterBase as BufferedDatasetWriterBase, + DatasetReaderBase as DatasetReaderBase, + DatasetWriterBase as DatasetWriterBase, + MemoryFileBase as MemoryFileBase, +) +from rasterio._typing import CRSInput, FileOrBytes +from rasterio.transform import TransformMethodsMixin +from rasterio.windows import WindowMethodsMixin + +class DatasetReader(DatasetReaderBase, WindowMethodsMixin, TransformMethodsMixin): ... +class DatasetWriter(DatasetWriterBase, WindowMethodsMixin, TransformMethodsMixin): ... +class BufferedDatasetWriter(BufferedDatasetWriterBase, WindowMethodsMixin, TransformMethodsMixin): ... + +class MemoryFile(MemoryFileBase): + def __init__( + self, + file_or_bytes: FileOrBytes | None = None, + dirname: str | None = None, + filename: str | None = None, + ext: str = ".tif", + ) -> None: ... + def open( + self, + driver: str | None = None, + width: int | None = None, + height: int | None = None, + count: int | None = None, + crs: CRSInput | None = None, + transform: Affine | None = None, + dtype: DTypeLike | None = None, + nodata: float | None = None, + sharing: bool = False, + thread_safe: bool = False, + **kwargs: Any, + ) -> DatasetReader | DatasetWriter: ... + def __enter__(self) -> Self: ... + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> bool | None: ... + +class ZipMemoryFile(MemoryFile): + def __init__(self, file_or_bytes: FileOrBytes | None = None) -> None: ... + # ZipMemoryFile.open takes `path` as a required positional arg, which + # breaks Liskov substitution with MemoryFile.open. This is intentional in + # rasterio. + def open( # type: ignore[override] + self, + path: str, + driver: str | None = None, + sharing: bool = False, + thread_safe: bool = False, + **kwargs: Any, + ) -> DatasetReader: ... + +@deprecated("FilePath is supplanted by rasterio.open's `opener` keyword argument and will be removed in 2.0.0.") +class FilePath(FilePathBase): + def __init__( + self, + filelike_obj: Any, + dirname: str | None = None, + filename: str | None = None, + ) -> None: ... + def open( + self, + driver: str | None = None, + sharing: bool = False, + thread_safe: bool = False, + **kwargs: Any, + ) -> DatasetReader: ... + def __enter__(self) -> Self: ... + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> bool | None: ... + +def get_writer_for_driver(driver: str) -> type[DatasetWriter | BufferedDatasetWriter] | None: ... +def get_writer_for_path( + path: str, + driver: str | None = None, +) -> type[DatasetWriter | BufferedDatasetWriter] | None: ... diff --git a/stubs/rasterio/rasterio/mask.pyi b/stubs/rasterio/rasterio/mask.pyi new file mode 100644 index 000000000000..bfb30da2077e --- /dev/null +++ b/stubs/rasterio/rasterio/mask.pyi @@ -0,0 +1,33 @@ +import logging +from collections.abc import Iterable, Mapping +from typing import Any, Final + +from numpy.typing import NDArray +from rasterio._affine_types import Affine +from rasterio.errors import WindowError as WindowError +from rasterio.features import geometry_mask as geometry_mask, geometry_window as geometry_window +from rasterio.io import DatasetReader + +logger: Final[logging.Logger] + +def raster_geometry_mask( + dataset: DatasetReader, + shapes: Iterable[Mapping[str, Any]], + all_touched: bool = False, + invert: bool = False, + crop: bool = False, + pad: bool = False, + pad_width: float = 0.5, +) -> tuple[NDArray[Any], Affine, tuple[int, int, int, int]]: ... +def mask( + dataset: DatasetReader, + shapes: Iterable[Mapping[str, Any]], + all_touched: bool = False, + invert: bool = False, + nodata: float | None = None, + filled: bool = True, + crop: bool = False, + pad: bool = False, + pad_width: float = 0.5, + indexes: int | Iterable[int] | None = None, +) -> tuple[NDArray[Any], Affine]: ... diff --git a/stubs/rasterio/rasterio/merge.pyi b/stubs/rasterio/rasterio/merge.pyi new file mode 100644 index 000000000000..ba1c68fe307b --- /dev/null +++ b/stubs/rasterio/rasterio/merge.pyi @@ -0,0 +1,63 @@ +import logging +import os +from collections.abc import Callable, Sequence +from typing import Any, Final, Literal, TypeAlias, overload +from typing_extensions import deprecated + +from numpy.typing import DTypeLike, NDArray +from rasterio._affine_types import Affine +from rasterio.enums import Resampling +from rasterio.io import DatasetReader + +logger: Final[logging.Logger] + +MethodFunction: TypeAlias = Callable[..., None] +MERGE_METHODS: Final[dict[str, MethodFunction]] + +_Arr: TypeAlias = NDArray[Any] + +def copy_first(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... +def copy_last(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... +def copy_min(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... +def copy_max(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... +def copy_sum(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... +def copy_count(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... +@overload +def merge( + sources: Sequence[DatasetReader | str | os.PathLike[str]], + bounds: tuple[float, float, float, float] | None = None, + res: float | tuple[float, float] | None = None, + nodata: float | None = None, + dtype: DTypeLike | None = None, + *, + indexes: int | Sequence[int] | None = None, + output_count: int | None = None, + resampling: Resampling = ..., + method: Literal["first", "last", "min", "max", "sum", "count"] | MethodFunction = "first", + target_aligned_pixels: bool = False, + mem_limit: int = 64, + use_highest_res: bool = False, + masked: bool = False, + dst_path: str | os.PathLike[str] | None = None, + dst_kwds: dict[str, Any] | None = None, +) -> tuple[NDArray[Any], Affine]: ... +@overload +@deprecated("The `precision` parameter is unused since rasterio 1.3 and will be removed in 2.0.0.") +def merge( + sources: Sequence[DatasetReader | str | os.PathLike[str]], + bounds: tuple[float, float, float, float] | None = None, + res: float | tuple[float, float] | None = None, + nodata: float | None = None, + dtype: DTypeLike | None = None, + precision: int | None = None, + indexes: int | Sequence[int] | None = None, + output_count: int | None = None, + resampling: Resampling = ..., + method: Literal["first", "last", "min", "max", "sum", "count"] | MethodFunction = "first", + target_aligned_pixels: bool = False, + mem_limit: int = 64, + use_highest_res: bool = False, + masked: bool = False, + dst_path: str | os.PathLike[str] | None = None, + dst_kwds: dict[str, Any] | None = None, +) -> tuple[NDArray[Any], Affine]: ... diff --git a/stubs/rasterio/rasterio/path.pyi b/stubs/rasterio/rasterio/path.pyi new file mode 100644 index 000000000000..94d9630d8af0 --- /dev/null +++ b/stubs/rasterio/rasterio/path.pyi @@ -0,0 +1,18 @@ +from typing import TypeAlias +from typing_extensions import deprecated + +from rasterio._path import _ParsedPath, _UnparsedPath +from rasterio.errors import RasterioDeprecationWarning as RasterioDeprecationWarning + +# The entire `rasterio.path` module is deprecated (the runtime emits a +# RasterioDeprecationWarning on import) and will be removed in a future +# rasterio release. Each re-export below is marked @deprecated so type +# checkers flag every call site, not just the import line. + +ParsedPath: TypeAlias = _ParsedPath +UnparsedPath: TypeAlias = _UnparsedPath + +@deprecated("rasterio.path.parse_path is deprecated; use rasterio._path._parse_path or pass paths directly to rasterio.open.") +def parse_path(path: str) -> _ParsedPath | _UnparsedPath: ... +@deprecated("rasterio.path.vsi_path is deprecated; use rasterio._path._vsi_path directly.") +def vsi_path(path: _ParsedPath | _UnparsedPath) -> str: ... diff --git a/stubs/rasterio/rasterio/plot.pyi b/stubs/rasterio/rasterio/plot.pyi new file mode 100644 index 000000000000..ef63bf8a2dbc --- /dev/null +++ b/stubs/rasterio/rasterio/plot.pyi @@ -0,0 +1,50 @@ +import logging +from collections.abc import Mapping, Sequence +from typing import Any, Final, Literal + +from numpy.typing import NDArray +from rasterio._affine_types import Affine +from rasterio.io import DatasetReader as DatasetReader +from rasterio.transform import guard_transform as guard_transform + +logger: Final[logging.Logger] + +def get_plt() -> Any: ... +def show( + source: NDArray[Any] | DatasetReader | tuple[DatasetReader, int], + with_bounds: bool = True, + contour: bool = False, + contour_label_kws: Mapping[str, Any] | None = None, + # New in rasterio 1.5: rgb composite band selection. + indexes: Sequence[int] | None = None, + ax: Any | None = None, + title: str | None = None, + transform: Affine | None = None, + # New in rasterio 1.5: histogram-stretch percentile range. + percent_range: tuple[float, float] | None = None, + adjust: bool = True, + **kwargs: Any, +) -> Any: ... +def plotting_extent( + source: NDArray[Any] | DatasetReader, + transform: Affine | None = None, +) -> tuple[float, float, float, float]: ... +def reshape_as_image(arr: NDArray[Any]) -> NDArray[Any]: ... +def reshape_as_raster(arr: NDArray[Any]) -> NDArray[Any]: ... +def show_hist( + source: NDArray[Any] | DatasetReader, + bins: int = 10, + masked: bool = True, + title: str = "Histogram", + ax: Any | None = None, + label: str | Sequence[str] | None = None, + range: tuple[float, float] | None = None, + **kwargs: Any, +) -> None: ... +def adjust_band(band: NDArray[Any], kind: Literal["linear", "log"] | None = None) -> NDArray[Any]: ... + +# Misspelled upstream (`strech` instead of `stretch`); preserved as-is. +def contrast_strech( + arr: NDArray[Any], + percent_range: tuple[float, float] = (2.0, 98.0), +) -> NDArray[Any]: ... diff --git a/stubs/rasterio/rasterio/profiles.pyi b/stubs/rasterio/rasterio/profiles.pyi new file mode 100644 index 000000000000..558ce1ced50c --- /dev/null +++ b/stubs/rasterio/rasterio/profiles.pyi @@ -0,0 +1,13 @@ +from collections import UserDict +from typing import Any, ClassVar, Final + +class Profile(UserDict[str, Any]): + defaults: ClassVar[dict[str, Any]] + def __init__(self, data: dict[str, Any] = ..., **kwds: Any) -> None: ... + def __getitem__(self, key: str) -> Any: ... + def __setitem__(self, key: str, val: Any) -> None: ... + +class DefaultGTiffProfile(Profile): + defaults: ClassVar[dict[str, Any]] + +default_gtiff_profile: Final[DefaultGTiffProfile] diff --git a/stubs/rasterio/rasterio/rpc.pyi b/stubs/rasterio/rasterio/rpc.pyi new file mode 100644 index 000000000000..b9e6d1e16ebe --- /dev/null +++ b/stubs/rasterio/rasterio/rpc.pyi @@ -0,0 +1,43 @@ +from collections.abc import Sequence +from typing import Any, Self + +class RPC: + height_off: float + height_scale: float + lat_off: float + lat_scale: float + line_den_coeff: Sequence[float] + line_num_coeff: Sequence[float] + line_off: float + line_scale: float + long_off: float + long_scale: float + samp_den_coeff: Sequence[float] + samp_num_coeff: Sequence[float] + samp_off: float + samp_scale: float + err_bias: float | None + err_rand: float | None + def __init__( + self, + height_off: float, + height_scale: float, + lat_off: float, + lat_scale: float, + line_den_coeff: Sequence[float], + line_num_coeff: Sequence[float], + line_off: float, + line_scale: float, + long_off: float, + long_scale: float, + samp_den_coeff: Sequence[float], + samp_num_coeff: Sequence[float], + samp_off: float, + samp_scale: float, + err_bias: float | None = None, + err_rand: float | None = None, + ) -> None: ... + def to_dict(self) -> dict[str, Any]: ... + def to_gdal(self) -> dict[str, str]: ... + @classmethod + def from_gdal(cls, rpcs: dict[str, str]) -> Self: ... diff --git a/stubs/rasterio/rasterio/sample.pyi b/stubs/rasterio/rasterio/sample.pyi new file mode 100644 index 000000000000..6cc7f2cb2576 --- /dev/null +++ b/stubs/rasterio/rasterio/sample.pyi @@ -0,0 +1,16 @@ +from collections.abc import Iterable, Iterator, Sequence +from typing import Any + +from numpy.typing import NDArray +from rasterio.io import DatasetReader + +def sample_gen( + dataset: DatasetReader, + xy: Iterable[tuple[float, float]], + indexes: int | Sequence[int] | None = None, + masked: bool = False, +) -> Iterator[NDArray[Any]]: ... + +# New in rasterio 1.5: sorts coordinates by x then y so callers of +# sample_gen can hint better dataset block access patterns. +def sort_xy(xy: Iterable[tuple[float, float]]) -> list[tuple[float, float]]: ... diff --git a/stubs/rasterio/rasterio/session.pyi b/stubs/rasterio/rasterio/session.pyi new file mode 100644 index 000000000000..f10a66f41c41 --- /dev/null +++ b/stubs/rasterio/rasterio/session.pyi @@ -0,0 +1,109 @@ +from typing import Any + +# CPLTestBool equivalent. Public utility re-exported from rasterio.session. +def parse_bool(v: bool | str | int) -> bool: ... + +class Session: + @classmethod + def hascreds(cls, config: dict[str, Any]) -> bool: ... + def get_credential_options(self) -> dict[str, str]: ... + @staticmethod + def from_foreign_session(session: Any, cls: type[Session] | None = None) -> Session: ... + @staticmethod + def cls_from_path(path: str) -> type[Session]: ... + @staticmethod + def from_path(path: str, *args: Any, **kwargs: Any) -> Session: ... + @staticmethod + def aws_or_dummy(*args: Any, **kwargs: Any) -> Session: ... + @staticmethod + def from_environ(*args: Any, **kwargs: Any) -> Session: ... + +class DummySession(Session): + credentials: dict[str, str] + def __init__(self, *args: Any, **kwargs: Any) -> None: ... + @classmethod + def hascreds(cls, config: dict[str, Any]) -> bool: ... + def get_credential_options(self) -> dict[str, str]: ... + +class AWSSession(Session): + requester_pays: bool + unsigned: bool + endpoint_url: str | None + def __init__( + self, + session: Any | None = None, + aws_unsigned: bool | None = None, + aws_access_key_id: str | None = None, + aws_secret_access_key: str | None = None, + aws_session_token: str | None = None, + region_name: str | None = None, + profile_name: str | None = None, + endpoint_url: str | None = None, + requester_pays: bool = False, + ) -> None: ... + @classmethod + def hascreds(cls, config: dict[str, Any]) -> bool: ... + @property + def credentials(self) -> dict[str, str]: ... + def get_credential_options(self) -> dict[str, str]: ... + +class OSSSession(Session): + def __init__( + self, + oss_access_key_id: str | None = None, + oss_secret_access_key: str | None = None, + oss_endpoint: str | None = None, + ) -> None: ... + @classmethod + def hascreds(cls, config: dict[str, Any]) -> bool: ... + @property + def credentials(self) -> dict[str, str]: ... + def get_credential_options(self) -> dict[str, str]: ... + +class GSSession(Session): + def __init__(self, google_application_credentials: str | None = None) -> None: ... + @classmethod + def hascreds(cls, config: dict[str, Any]) -> bool: ... + @property + def credentials(self) -> dict[str, str]: ... + def get_credential_options(self) -> dict[str, str]: ... + +class SwiftSession(Session): + def __init__( + self, + session: Any | None = None, + swift_storage_url: str | None = None, + swift_auth_token: str | None = None, + swift_auth_v1_url: str | None = None, + swift_user: str | None = None, + swift_key: str | None = None, + ) -> None: ... + @classmethod + def hascreds(cls, config: dict[str, Any]) -> bool: ... + @property + def credentials(self) -> dict[str, str]: ... + def get_credential_options(self) -> dict[str, str]: ... + +class AzureSession(Session): + unsigned: bool + storage_account: str | None + # Expanded in rasterio 1.5: added access_token, sas_token, tenant_id, + # client_id, federated_token_file, and authority_host parameters. + def __init__( + self, + azure_storage_connection_string: str | None = None, + azure_storage_account: str | None = None, + azure_storage_access_token: str | None = None, + azure_storage_access_key: str | None = None, + azure_storage_sas_token: str | None = None, + azure_unsigned: bool = False, + azure_tenant_id: str | None = None, + azure_client_id: str | None = None, + azure_federated_token_file: str | None = None, + azure_authority_host: str | None = None, + ) -> None: ... + @classmethod + def hascreds(cls, config: dict[str, Any]) -> bool: ... + @property + def credentials(self) -> dict[str, str]: ... + def get_credential_options(self) -> dict[str, str]: ... diff --git a/stubs/rasterio/rasterio/shutil.pyi b/stubs/rasterio/rasterio/shutil.pyi new file mode 100644 index 000000000000..f0da0b6e2e99 --- /dev/null +++ b/stubs/rasterio/rasterio/shutil.pyi @@ -0,0 +1,13 @@ +import os +from typing import Any + +def exists(path: str | os.PathLike[str]) -> bool: ... +def copy( + src: str | os.PathLike[str] | Any, + dst: str | os.PathLike[str], + driver: str | None = None, + strict: bool = True, + **creation_options: Any, +) -> None: ... +def copyfiles(src: str | os.PathLike[str], dst: str | os.PathLike[str]) -> None: ... +def delete(path: str | os.PathLike[str], driver: str | None = None) -> None: ... diff --git a/stubs/rasterio/rasterio/stack.pyi b/stubs/rasterio/rasterio/stack.pyi new file mode 100644 index 000000000000..56a1553c55c9 --- /dev/null +++ b/stubs/rasterio/rasterio/stack.pyi @@ -0,0 +1,28 @@ +import logging +import os +from collections.abc import Sequence +from typing import Any, Final + +from numpy.typing import DTypeLike, NDArray +from rasterio._affine_types import Affine +from rasterio.enums import Resampling +from rasterio.io import DatasetReader + +logger: Final[logging.Logger] + +def stack( + sources: Sequence[DatasetReader | str | os.PathLike[str]], + bounds: tuple[float, float, float, float] | None = None, + res: float | tuple[float, float] | None = None, + nodata: float | None = None, + dtype: DTypeLike | None = None, + indexes: int | Sequence[int] | None = None, + output_count: int | None = None, + resampling: Resampling = ..., + target_aligned_pixels: bool = False, + mem_limit: int = 64, + use_highest_res: bool = False, + masked: bool = False, + dst_path: str | os.PathLike[str] | None = None, + dst_kwds: dict[str, Any] | None = None, +) -> tuple[NDArray[Any], Affine]: ... diff --git a/stubs/rasterio/rasterio/tools.pyi b/stubs/rasterio/rasterio/tools.pyi new file mode 100644 index 000000000000..0d78bca77964 --- /dev/null +++ b/stubs/rasterio/rasterio/tools.pyi @@ -0,0 +1,19 @@ +import os +from collections.abc import Callable, Iterable +from typing import Any, Final + +class JSONSequenceTool: + func: Callable[..., Iterable[Any]] + def __init__(self, func: Callable[..., Iterable[Any]]) -> None: ... + def __call__( + self, + src_path: str | os.PathLike[str], + dst_path: str | os.PathLike[str], + src_kwargs: dict[str, Any] | None = None, + dst_kwargs: dict[str, Any] | None = None, + func_args: Iterable[Any] | None = None, + func_kwargs: dict[str, Any] | None = None, + config: dict[str, Any] | None = None, + ) -> None: ... + +dataset_features_tool: Final[JSONSequenceTool] diff --git a/stubs/rasterio/rasterio/transform.pyi b/stubs/rasterio/rasterio/transform.pyi new file mode 100644 index 000000000000..d39af8d9e452 --- /dev/null +++ b/stubs/rasterio/rasterio/transform.pyi @@ -0,0 +1,119 @@ +from collections.abc import Callable, Sequence +from typing import Any, Final, Literal, Self, TypeAlias, overload +from typing_extensions import deprecated + +from rasterio._affine_types import Affine as Affine +from rasterio._transform import GCPTransformerBase, RPCTransformerBase +from rasterio.control import GroundControlPoint +from rasterio.enums import TransformDirection as TransformDirection, TransformMethod as TransformMethod +from rasterio.errors import RasterioDeprecationWarning as RasterioDeprecationWarning +from rasterio.rpc import RPC + +_Sextuple: TypeAlias = tuple[float, float, float, float, float, float] +_OffsetOptions: TypeAlias = Literal["center", "ul", "ur", "ll", "lr"] +_RoundOperation: TypeAlias = Callable[[float], int] + +IDENTITY: Final[Affine] +GDAL_IDENTITY: Final[_Sextuple] + +class TransformMethodsMixin: + def xy( + self, + row: int | Sequence[int], + col: int | Sequence[int], + z: float | Sequence[float] | None = None, + offset: _OffsetOptions = "center", + transform_method: TransformMethod = ..., + **rpc_options: Any, + ) -> tuple[float, float] | tuple[list[float], list[float]]: ... + # NOTE: `precision=` is deprecated since rasterio 1.3 and silently + # ignored at runtime (a DeprecationWarning is emitted). We do not + # express this with @deprecated overloads here because `**rpc_options` + # would swallow the deprecated kwarg in the modern overload, defeating + # the overload resolution. Type checkers can therefore not flag + # `precision=` callers; the runtime warning is the only signal. + def index( + self, + x: float | Sequence[float], + y: float | Sequence[float], + z: float | Sequence[float] | None = None, + op: _RoundOperation | None = None, + precision: int | None = None, + transform_method: TransformMethod = ..., + **rpc_options: Any, + ) -> tuple[int, int] | tuple[list[int], list[int]]: ... + +def tastes_like_gdal(seq: Affine | _Sextuple) -> bool: ... +def guard_transform(transform: Affine | _Sextuple) -> Affine: ... +def from_origin(west: float, north: float, xsize: float, ysize: float) -> Affine: ... +def from_bounds(west: float, south: float, east: float, north: float, width: float, height: float) -> Affine: ... +def array_bounds(height: int, width: int, transform: Affine) -> tuple[float, float, float, float]: ... +def from_gcps(gcps: Sequence[GroundControlPoint]) -> Affine: ... +def xy( + transform: Affine | Sequence[GroundControlPoint] | RPC, + rows: int | Sequence[int], + cols: int | Sequence[int], + zs: float | Sequence[float] | None = None, + offset: _OffsetOptions = "center", + **rpc_options: Any, +) -> tuple[float, float] | tuple[list[float], list[float]]: ... + +# NOTE: `precision=` is deprecated since rasterio 1.3 and a no-op (runtime +# emits a DeprecationWarning). Not expressed via @deprecated overload here +# because `**rpc_options` would swallow it in the modern overload. +def rowcol( + transform: Affine | Sequence[GroundControlPoint] | RPC, + xs: float | Sequence[float], + ys: float | Sequence[float], + zs: float | Sequence[float] | None = None, + op: _RoundOperation | None = None, + precision: int | None = None, + **rpc_options: Any, +) -> tuple[int, int] | tuple[list[int], list[int]]: ... +def get_transformer( + transform: Affine | Sequence[GroundControlPoint] | RPC, + **rpc_options: Any, +) -> type[TransformerBase]: ... + +class TransformerBase: + def __init__(self) -> None: ... + def xy( + self, + rows: int | Sequence[int], + cols: int | Sequence[int], + zs: float | Sequence[float] | None = None, + offset: _OffsetOptions = "center", + ) -> tuple[float, float] | tuple[list[float], list[float]]: ... + @overload + def rowcol( + self, + xs: float | Sequence[float], + ys: float | Sequence[float], + zs: float | Sequence[float] | None = None, + op: _RoundOperation | None = None, + ) -> tuple[int, int] | tuple[list[int], list[int]]: ... + @overload + @deprecated("The `precision` parameter is unused since rasterio 1.3 and will be removed in 2.0.0.") + def rowcol( + self, + xs: float | Sequence[float], + ys: float | Sequence[float], + zs: float | Sequence[float] | None = None, + op: _RoundOperation | None = None, + precision: int | None = None, + ) -> tuple[int, int] | tuple[list[int], list[int]]: ... + +class GDALTransformerBase(TransformerBase): + def __init__(self) -> None: ... + def close(self) -> None: ... + def __enter__(self) -> Self: ... + def __exit__(self, *args: object) -> None: ... + +class AffineTransformer(TransformerBase): + def __init__(self, affine_transform: Affine | _Sextuple) -> None: ... + +class GCPTransformer(GCPTransformerBase, GDALTransformerBase): + def __init__(self, gcps: Sequence[GroundControlPoint], tps: bool = False) -> None: ... + +class RPCTransformer(RPCTransformerBase, GDALTransformerBase): + def __init__(self, rpcs: RPC, **rpc_options: Any) -> None: ... diff --git a/stubs/rasterio/rasterio/vrt.pyi b/stubs/rasterio/rasterio/vrt.pyi new file mode 100644 index 000000000000..79a5ada416b9 --- /dev/null +++ b/stubs/rasterio/rasterio/vrt.pyi @@ -0,0 +1,16 @@ +from types import TracebackType +from typing import Self + +from rasterio._warp import WarpedVRTReaderBase +from rasterio.transform import TransformMethodsMixin +from rasterio.windows import WindowMethodsMixin + +class WarpedVRT(WarpedVRTReaderBase, WindowMethodsMixin, TransformMethodsMixin): + def __enter__(self) -> Self: ... + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: ... + def __del__(self) -> None: ... diff --git a/stubs/rasterio/rasterio/warp.pyi b/stubs/rasterio/rasterio/warp.pyi new file mode 100644 index 000000000000..be6c70aac54f --- /dev/null +++ b/stubs/rasterio/rasterio/warp.pyi @@ -0,0 +1,107 @@ +from _typeshed import Incomplete +from collections.abc import Mapping, Sequence +from typing import Any, Final, TypeAlias, overload +from typing_extensions import deprecated + +from numpy.typing import ArrayLike, NDArray +from rasterio._affine_types import Affine +from rasterio._typing import CRSInput +from rasterio.control import GroundControlPoint +from rasterio.enums import Resampling +from rasterio.rpc import RPC + +_Resolution: TypeAlias = tuple[float, float] | float +_Gcps: TypeAlias = Sequence[GroundControlPoint] +_Rpcs: TypeAlias = RPC | Mapping[str, Any] + +SUPPORTED_RESAMPLING: Final[list[Resampling]] + +def transform( + src_crs: CRSInput, + dst_crs: CRSInput, + xs: ArrayLike, + ys: ArrayLike, + zs: ArrayLike | None = None, +) -> tuple[list[float], list[float]] | tuple[list[float], list[float], list[float]]: ... + +# In rasterio 1.5 `antimeridian_cutting` and `antimeridian_offset` are +# deprecated (they have been no-ops since GDAL 2.2). The modern overload +# accepts only `precision`; the legacy overload accepts the antimeridian +# kwargs and is marked @deprecated so type checkers surface a warning at +# call sites that still pass them. +@overload +def transform_geom( + src_crs: CRSInput, + dst_crs: CRSInput, + geom: Mapping[str, Any] | Sequence[Mapping[str, Any]], + *, + precision: float = -1, +) -> dict[str, Any] | list[dict[str, Any]]: ... +@overload +@deprecated( + "`antimeridian_cutting` and `antimeridian_offset` are no-ops since GDAL 2.2 " + "and will be removed in a future rasterio release. Call transform_geom " + "without them." +) +def transform_geom( + src_crs: CRSInput, + dst_crs: CRSInput, + geom: Mapping[str, Any] | Sequence[Mapping[str, Any]], + antimeridian_cutting: bool | None = None, + antimeridian_offset: float | None = None, + precision: float = -1, +) -> dict[str, Any] | list[dict[str, Any]]: ... +def transform_bounds( + src_crs: CRSInput, + dst_crs: CRSInput, + left: float, + bottom: float, + right: float, + top: float, + densify_pts: int = 21, +) -> tuple[float, float, float, float]: ... +def reproject( + source: ArrayLike | Incomplete, + destination: ArrayLike | Incomplete | None = None, + src_transform: Affine | None = None, + gcps: _Gcps | None = None, + rpcs: _Rpcs | None = None, + src_crs: CRSInput | None = None, + src_nodata: float | None = None, + dst_transform: Affine | None = None, + dst_crs: CRSInput | None = None, + dst_nodata: float | None = None, + dst_resolution: _Resolution | None = None, + src_alpha: int = 0, + dst_alpha: int = 0, + masked: bool = False, + resampling: Resampling = ..., + num_threads: int = 1, + init_dest_nodata: bool = True, + warp_mem_limit: int = 0, + src_geoloc_array: NDArray[Any] | None = None, + **kwargs: Any, +) -> tuple[NDArray[Any], Affine]: ... +def aligned_target( + transform: Affine, + width: int, + height: int, + resolution: _Resolution, +) -> tuple[Affine, int, int]: ... +def calculate_default_transform( + src_crs: CRSInput, + dst_crs: CRSInput, + width: int, + height: int, + left: float | None = None, + bottom: float | None = None, + right: float | None = None, + top: float | None = None, + gcps: _Gcps | None = None, + rpcs: _Rpcs | None = None, + resolution: _Resolution | None = None, + dst_width: int | None = None, + dst_height: int | None = None, + src_geoloc_array: NDArray[Any] | None = None, + **kwargs: Any, +) -> tuple[Affine, int, int]: ... diff --git a/stubs/rasterio/rasterio/windows.pyi b/stubs/rasterio/rasterio/windows.pyi new file mode 100644 index 000000000000..24b855e69014 --- /dev/null +++ b/stubs/rasterio/rasterio/windows.pyi @@ -0,0 +1,100 @@ +from collections.abc import Callable, Sequence +from typing import Any, Self, TypeAlias, overload +from typing_extensions import deprecated + +from numpy.typing import NDArray +from rasterio._affine_types import Affine +from rasterio.errors import RasterioDeprecationWarning as RasterioDeprecationWarning, WindowError as WindowError + +_Bounds: TypeAlias = tuple[float, float, float, float] +_Ranges: TypeAlias = tuple[tuple[int, int], tuple[int, int]] +_Slices: TypeAlias = tuple[slice, slice] + +class WindowMethodsMixin: + @overload + def window(self, left: float, bottom: float, right: float, top: float) -> Window: ... + @overload + @deprecated("The `precision` parameter is unused since rasterio 1.3 and will be removed in 2.0.0.") + def window( + self, + left: float, + bottom: float, + right: float, + top: float, + precision: int | None = None, + ) -> Window: ... + def window_transform(self, window: Window) -> Affine: ... + def window_bounds(self, window: Window) -> _Bounds: ... + +def iter_args(function: Callable[..., Any]) -> Callable[..., Any]: ... +def toranges(window: Window | _Ranges) -> _Ranges: ... +def get_data_window(arr: NDArray[Any], nodata: float | None = None) -> Window: ... +def union(*windows: Window) -> Window: ... +def intersection(*windows: Window) -> Window: ... +def intersect(*windows: Window) -> bool: ... +@overload +def from_bounds( + left: float, + bottom: float, + right: float, + top: float, + transform: Affine | None = None, +) -> Window: ... +@overload +@deprecated( + "`height`, `width`, and `precision` on windows.from_bounds are unused since rasterio 1.3 and will be removed in 2.0.0." +) +def from_bounds( + left: float, + bottom: float, + right: float, + top: float, + transform: Affine | None = None, + height: int | None = None, + width: int | None = None, + precision: int | None = None, +) -> Window: ... +def transform(window: Window, transform: Affine) -> Affine: ... +def bounds(window: Window, transform: Affine, height: int = 0, width: int = 0) -> _Bounds: ... +def crop(window: Window, height: int, width: int) -> Window: ... +def evaluate(window: Window, height: int, width: int, boundless: bool = False) -> Window: ... +def shape(window: Window, height: int = -1, width: int = -1) -> tuple[int, int]: ... +def window_index(window: Window, height: int = 0, width: int = 0) -> _Slices: ... +def round_window_to_full_blocks( + window: Window, + block_shapes: Sequence[tuple[int, int]], + height: int = 0, + width: int = 0, +) -> Window: ... +def validate_length_value(instance: object, attribute: object, value: float) -> None: ... +def subdivide(window: Window, height: int, width: int) -> list[Window]: ... + +class Window: + col_off: float + row_off: float + width: float + height: float + def __init__(self, col_off: float, row_off: float, width: float, height: float) -> None: ... + def flatten(self) -> tuple[float, float, float, float]: ... + def todict(self) -> dict[str, float]: ... + def toranges(self) -> _Ranges: ... + def toslices(self) -> _Slices: ... + @classmethod + def from_slices( + cls, + rows: slice | Sequence[int], + cols: slice | Sequence[int], + height: int = -1, + width: int = -1, + boundless: bool = False, + ) -> Self: ... + # The runtime accepts arbitrary kwargs (op, pixel_precision) for these + # methods to preserve backwards compatibility while emitting deprecation + # warnings. We type them as **kwds to match. + def round_lengths(self, **kwds: Any) -> Window: ... + @deprecated("Window.round_shape is deprecated and will be removed in Rasterio 2.0.0; use round_lengths instead.") + def round_shape(self, **kwds: Any) -> Window: ... + def round_offsets(self, **kwds: Any) -> Window: ... + def round(self, ndigits: int | None = None) -> Window: ... + def crop(self, height: int, width: int) -> Window: ... + def intersection(self, other: Window) -> Window: ... From e703f5d16e2673cb01902b2f16cf0c304dcf3da7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 8 Jun 2026 16:43:44 +0000 Subject: [PATCH 2/7] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stubs/rasterio/rasterio/__init__.pyi | 6 +--- stubs/rasterio/rasterio/_base.pyi | 34 ++++++++++--------- stubs/rasterio/rasterio/_io.pyi | 48 +++++---------------------- stubs/rasterio/rasterio/_warp.pyi | 13 ++------ stubs/rasterio/rasterio/crs.pyi | 6 +--- stubs/rasterio/rasterio/features.pyi | 32 ++++-------------- stubs/rasterio/rasterio/io.pyi | 41 ++++------------------- stubs/rasterio/rasterio/merge.pyi | 1 + stubs/rasterio/rasterio/plot.pyi | 8 ++--- stubs/rasterio/rasterio/sample.pyi | 5 +-- stubs/rasterio/rasterio/session.pyi | 5 +-- stubs/rasterio/rasterio/transform.pyi | 6 ++-- stubs/rasterio/rasterio/vrt.pyi | 5 +-- stubs/rasterio/rasterio/warp.pyi | 28 +++------------- stubs/rasterio/rasterio/windows.pyi | 32 ++++-------------- 15 files changed, 64 insertions(+), 206 deletions(-) diff --git a/stubs/rasterio/rasterio/__init__.pyi b/stubs/rasterio/rasterio/__init__.pyi index f1bf2d1276a7..9f68a8618ceb 100644 --- a/stubs/rasterio/rasterio/__init__.pyi +++ b/stubs/rasterio/rasterio/__init__.pyi @@ -126,9 +126,5 @@ class Band(NamedTuple): def band(ds: AnyDataset, bidx: int | Sequence[int]) -> Band: ... def pad( - array: NDArray[Any], - transform: Affine, - pad_width: int, - mode: str | Callable[..., Any] | None = None, - **kwargs: Any, + array: NDArray[Any], transform: Affine, pad_width: int, mode: str | Callable[..., Any] | None = None, **kwargs: Any ) -> tuple[NDArray[Any], Affine]: ... diff --git a/stubs/rasterio/rasterio/_base.pyi b/stubs/rasterio/rasterio/_base.pyi index 6ad153393b2f..985e8627c693 100644 --- a/stubs/rasterio/rasterio/_base.pyi +++ b/stubs/rasterio/rasterio/_base.pyi @@ -28,11 +28,7 @@ def tastes_like_gdal(seq: Affine | Sequence[float]) -> bool: ... def _raster_driver_extensions() -> dict[str, str]: ... def _can_create_osr(crs: CRSInput) -> bool: ... def _transform( - src_crs: CRSInput, - dst_crs: CRSInput, - xs: Sequence[float], - ys: Sequence[float], - zs: Sequence[float] | None, + src_crs: CRSInput, dst_crs: CRSInput, xs: Sequence[float], ys: Sequence[float], zs: Sequence[float] | None ) -> tuple[list[float], list[float], list[float]]: ... class DatasetBase: @@ -54,10 +50,7 @@ class DatasetBase: ) -> None: ... def __enter__(self) -> Self: ... def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None ) -> None: ... def read_crs(self) -> CRS | None: ... def read_transform(self) -> list[float]: ... @@ -77,37 +70,47 @@ class DatasetBase: def get_nodatavals(self) -> tuple[float | None, ...]: ... @property def nodatavals(self) -> tuple[float | None, ...]: ... + @property def nodata(self) -> float | None: ... @nodata.setter def nodata(self, value: float | None) -> None: ... + @property def mask_flag_enums(self) -> tuple[list[MaskFlags], ...]: ... + @property def crs(self) -> CRS: ... @crs.setter def crs(self, value: CRSInput) -> None: ... + @property def descriptions(self) -> tuple[str | None, ...]: ... @descriptions.setter def descriptions(self, value: Sequence[str | None]) -> None: ... + def write_transform(self, transform: Sequence[float]) -> None: ... + @property def transform(self) -> Affine: ... @transform.setter def transform(self, value: Affine) -> None: ... + @property def offsets(self) -> tuple[float, ...]: ... @offsets.setter def offsets(self, value: Sequence[float]) -> None: ... + @property def scales(self) -> tuple[float, ...]: ... @scales.setter def scales(self, value: Sequence[float]) -> None: ... + @property def units(self) -> tuple[str | None, ...]: ... @units.setter def units(self, value: Sequence[str | None]) -> None: ... + def block_window(self, bidx: int, i: int, j: int) -> Window: ... def block_size(self, bidx: int, i: int, j: int) -> int: ... def block_windows(self, bidx: int = 0) -> Iterable[tuple[tuple[int, int], Window]]: ... @@ -134,29 +137,28 @@ class DatasetBase: def subdatasets(self) -> list[str]: ... def tag_namespaces(self, bidx: int = 0) -> list[str]: ... def tags(self, bidx: int = 0, ns: str | None = None) -> dict[str, str]: ... - def get_tag_item( - self, - ns: str, - dm: str | None = None, - bidx: int = 0, - ovr: int | None = None, - ) -> str | None: ... + def get_tag_item(self, ns: str, dm: str | None = None, bidx: int = 0, ovr: int | None = None) -> str | None: ... + @property def colorinterp(self) -> tuple[ColorInterp, ...]: ... @colorinterp.setter def colorinterp(self, value: Sequence[ColorInterp]) -> None: ... + def colormap(self, bidx: int) -> Colormap: ... def overviews(self, bidx: int) -> list[int]: ... def checksum(self, bidx: int, window: Window | None = None) -> int: ... def get_gcps(self) -> tuple[list[GroundControlPoint], CRS]: ... + @property def gcps(self) -> tuple[list[GroundControlPoint], CRS]: ... @gcps.setter def gcps(self, value: tuple[Sequence[GroundControlPoint], CRSInput]) -> None: ... + @property def rpcs(self) -> RPC | None: ... @rpcs.setter def rpcs(self, value: RPC | None) -> None: ... + @property def files(self) -> list[str]: ... diff --git a/stubs/rasterio/rasterio/_io.pyi b/stubs/rasterio/rasterio/_io.pyi index 47ebe0805a89..4276dd557c84 100644 --- a/stubs/rasterio/rasterio/_io.pyi +++ b/stubs/rasterio/rasterio/_io.pyi @@ -34,10 +34,7 @@ def _boundless_vrt_doc( resampling: Resampling = ..., ) -> str: ... def sample_gen( - dataset: DatasetBase, - xy: Sequence[tuple[float, float]], - indexes: Indexes | None = None, - masked: bool = False, + dataset: DatasetBase, xy: Sequence[tuple[float, float]], indexes: Indexes | None = None, masked: bool = False ) -> Iterator[NDArray[Any]]: ... class Statistics: @@ -78,10 +75,7 @@ class DatasetReaderBase(DatasetBase): resampling: Resampling = ..., ) -> NDArray[Any]: ... def sample( - self, - xy: Sequence[tuple[float, float]], - indexes: Indexes | None = None, - masked: bool = False, + self, xy: Sequence[tuple[float, float]], indexes: Indexes | None = None, masked: bool = False ) -> Iterator[NDArray[Any]]: ... def stats(self, *, indexes: Indexes | None = None, approx: bool = False) -> list[Statistics]: ... @deprecated("DatasetReaderBase.statistics() will be removed in 2.0.0; please switch to stats().") @@ -133,43 +127,17 @@ class DatasetWriterBase(DatasetReaderBase): **kwargs: Any, ) -> None: ... def write( - self, - arr: NDArray[Any], - indexes: Indexes | None = None, - window: WindowInput | None = None, - masked: bool = False, - ) -> None: ... - def write_band( - self, - bidx: int, - src: NDArray[Any], - window: WindowInput | None = None, - ) -> None: ... - def update_tags( - self, - bidx: int = 0, - ns: str | None = None, - **kwargs: Any, + self, arr: NDArray[Any], indexes: Indexes | None = None, window: WindowInput | None = None, masked: bool = False ) -> None: ... + def write_band(self, bidx: int, src: NDArray[Any], window: WindowInput | None = None) -> None: ... + def update_tags(self, bidx: int = 0, ns: str | None = None, **kwargs: Any) -> None: ... def set_band_description(self, bidx: int, value: str) -> None: ... def set_band_unit(self, bidx: int, value: str) -> None: ... def write_colormap(self, bidx: int, colormap: Colormap) -> None: ... - def write_mask( - self, - mask_array: NDArray[Any], - window: WindowInput | None = None, - ) -> None: ... - def build_overviews( - self, - factors: Sequence[int], - resampling: Resampling = ..., - ) -> None: ... + def write_mask(self, mask_array: NDArray[Any], window: WindowInput | None = None) -> None: ... + def build_overviews(self, factors: Sequence[int], resampling: Resampling = ...) -> None: ... def update_stats( - self, - *, - stats: Sequence[Statistics] | None = None, - indexes: Indexes | None = None, - approx: bool = False, + self, *, stats: Sequence[Statistics] | None = None, indexes: Indexes | None = None, approx: bool = False ) -> None: ... def clear_stats(self) -> None: ... diff --git a/stubs/rasterio/rasterio/_warp.pyi b/stubs/rasterio/rasterio/_warp.pyi index 11f355dd933a..c7e4e003879c 100644 --- a/stubs/rasterio/rasterio/_warp.pyi +++ b/stubs/rasterio/rasterio/_warp.pyi @@ -16,10 +16,7 @@ DEFAULT_NODATA_FLAG: Final[object] def recursive_round(val: Any, precision: int) -> Any: ... def _transform_geom( - src_crs: CRSInput, - dst_crs: CRSInput, - geom: Mapping[str, Any] | Sequence[Mapping[str, Any]], - precision: int, + src_crs: CRSInput, dst_crs: CRSInput, geom: Mapping[str, Any] | Sequence[Mapping[str, Any]], precision: int ) -> dict[str, Any] | list[dict[str, Any]]: ... def _reproject( source: NDArray[Any] | Any, @@ -58,13 +55,7 @@ def _calculate_default_transform( **kwargs: Any, ) -> tuple[Affine, int, int]: ... def _transform_bounds( - src_crs: CRS, - dst_crs: CRS, - left: float, - bottom: float, - right: float, - top: float, - densify_pts: int, + src_crs: CRS, dst_crs: CRS, left: float, bottom: float, right: float, top: float, densify_pts: int ) -> tuple[float, float, float, float]: ... def _suggested_proxy_vrt_doc( width: int, diff --git a/stubs/rasterio/rasterio/crs.pyi b/stubs/rasterio/rasterio/crs.pyi index 1b166afb54c2..a2fdc6655dd2 100644 --- a/stubs/rasterio/rasterio/crs.pyi +++ b/stubs/rasterio/rasterio/crs.pyi @@ -22,11 +22,7 @@ class CRS(Mapping[str, Any]): def __getstate__(self) -> dict[str, Any]: ... def __setstate__(self, state: Mapping[str, Any]) -> None: ... def to_proj4(self) -> str: ... - def to_wkt( - self, - morph_to_esri_dialect: bool = False, - version: WktVersion | str | None = None, - ) -> str: ... + def to_wkt(self, morph_to_esri_dialect: bool = False, version: WktVersion | str | None = None) -> str: ... @property def wkt(self) -> str: ... def to_epsg(self, confidence_threshold: int = 70) -> int | None: ... diff --git a/stubs/rasterio/rasterio/features.pyi b/stubs/rasterio/rasterio/features.pyi index 2eab145af009..cf1d5910c78d 100644 --- a/stubs/rasterio/rasterio/features.pyi +++ b/stubs/rasterio/rasterio/features.pyi @@ -14,24 +14,13 @@ from rasterio.windows import Window as Window Geometry: TypeAlias = Mapping[str, Any] def geometry_mask( - geometries: Iterable[Geometry], - out_shape: tuple[int, int], - transform: Affine, - all_touched: bool = False, - invert: bool = False, + geometries: Iterable[Geometry], out_shape: tuple[int, int], transform: Affine, all_touched: bool = False, invert: bool = False ) -> NDArray[np.bool_]: ... def shapes( - source: NDArray[Any], - mask: NDArray[np.bool_] | None = None, - connectivity: int = 4, - transform: Affine = ..., + source: NDArray[Any], mask: NDArray[np.bool_] | None = None, connectivity: int = 4, transform: Affine = ... ) -> Iterator[tuple[dict[str, Any], float | int]]: ... def sieve( - source: NDArray[Any], - size: int, - out: NDArray[Any] | None = None, - mask: NDArray[np.bool_] | None = None, - connectivity: int = 4, + source: NDArray[Any], size: int, out: NDArray[Any] | None = None, mask: NDArray[np.bool_] | None = None, connectivity: int = 4 ) -> NDArray[Any]: ... def rasterize( shapes: Iterable[tuple[Geometry, float] | Geometry], @@ -49,19 +38,11 @@ def rasterize( dst_path: str | os.PathLike[str] | None = None, dst_kwds: dict[str, Any] | None = None, ) -> NDArray[Any]: ... -def bounds( - geometry: Geometry, - north_up: bool = True, - transform: Affine | None = None, -) -> tuple[float, float, float, float]: ... +def bounds(geometry: Geometry, north_up: bool = True, transform: Affine | None = None) -> tuple[float, float, float, float]: ... + @overload def geometry_window( - dataset: DatasetReader, - shapes: Iterable[Geometry], - pad_x: float = 0, - pad_y: float = 0, - *, - boundless: bool = False, + dataset: DatasetReader, shapes: Iterable[Geometry], pad_x: float = 0, pad_y: float = 0, *, boundless: bool = False ) -> Window: ... @overload @deprecated( @@ -78,6 +59,7 @@ def geometry_window( pixel_precision: float | None = None, boundless: bool = False, ) -> Window: ... + def is_valid_geom(geom: Geometry) -> bool: ... def dataset_features( src: DatasetReader, diff --git a/stubs/rasterio/rasterio/io.pyi b/stubs/rasterio/rasterio/io.pyi index 51da8bf40bfc..f48e5bf3e34e 100644 --- a/stubs/rasterio/rasterio/io.pyi +++ b/stubs/rasterio/rasterio/io.pyi @@ -21,11 +21,7 @@ class BufferedDatasetWriter(BufferedDatasetWriterBase, WindowMethodsMixin, Trans class MemoryFile(MemoryFileBase): def __init__( - self, - file_or_bytes: FileOrBytes | None = None, - dirname: str | None = None, - filename: str | None = None, - ext: str = ".tif", + self, file_or_bytes: FileOrBytes | None = None, dirname: str | None = None, filename: str | None = None, ext: str = ".tif" ) -> None: ... def open( self, @@ -43,10 +39,7 @@ class MemoryFile(MemoryFileBase): ) -> DatasetReader | DatasetWriter: ... def __enter__(self) -> Self: ... def __exit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - traceback: TracebackType | None, + self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None ) -> bool | None: ... class ZipMemoryFile(MemoryFile): @@ -55,39 +48,19 @@ class ZipMemoryFile(MemoryFile): # breaks Liskov substitution with MemoryFile.open. This is intentional in # rasterio. def open( # type: ignore[override] - self, - path: str, - driver: str | None = None, - sharing: bool = False, - thread_safe: bool = False, - **kwargs: Any, + self, path: str, driver: str | None = None, sharing: bool = False, thread_safe: bool = False, **kwargs: Any ) -> DatasetReader: ... @deprecated("FilePath is supplanted by rasterio.open's `opener` keyword argument and will be removed in 2.0.0.") class FilePath(FilePathBase): - def __init__( - self, - filelike_obj: Any, - dirname: str | None = None, - filename: str | None = None, - ) -> None: ... + def __init__(self, filelike_obj: Any, dirname: str | None = None, filename: str | None = None) -> None: ... def open( - self, - driver: str | None = None, - sharing: bool = False, - thread_safe: bool = False, - **kwargs: Any, + self, driver: str | None = None, sharing: bool = False, thread_safe: bool = False, **kwargs: Any ) -> DatasetReader: ... def __enter__(self) -> Self: ... def __exit__( - self, - exc_type: type[BaseException] | None, - exc_value: BaseException | None, - traceback: TracebackType | None, + self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None ) -> bool | None: ... def get_writer_for_driver(driver: str) -> type[DatasetWriter | BufferedDatasetWriter] | None: ... -def get_writer_for_path( - path: str, - driver: str | None = None, -) -> type[DatasetWriter | BufferedDatasetWriter] | None: ... +def get_writer_for_path(path: str, driver: str | None = None) -> type[DatasetWriter | BufferedDatasetWriter] | None: ... diff --git a/stubs/rasterio/rasterio/merge.pyi b/stubs/rasterio/rasterio/merge.pyi index ba1c68fe307b..2a29936406d0 100644 --- a/stubs/rasterio/rasterio/merge.pyi +++ b/stubs/rasterio/rasterio/merge.pyi @@ -22,6 +22,7 @@ def copy_min(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Ar def copy_max(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... def copy_sum(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... def copy_count(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... + @overload def merge( sources: Sequence[DatasetReader | str | os.PathLike[str]], diff --git a/stubs/rasterio/rasterio/plot.pyi b/stubs/rasterio/rasterio/plot.pyi index ef63bf8a2dbc..aafc07ccd5dc 100644 --- a/stubs/rasterio/rasterio/plot.pyi +++ b/stubs/rasterio/rasterio/plot.pyi @@ -26,8 +26,7 @@ def show( **kwargs: Any, ) -> Any: ... def plotting_extent( - source: NDArray[Any] | DatasetReader, - transform: Affine | None = None, + source: NDArray[Any] | DatasetReader, transform: Affine | None = None ) -> tuple[float, float, float, float]: ... def reshape_as_image(arr: NDArray[Any]) -> NDArray[Any]: ... def reshape_as_raster(arr: NDArray[Any]) -> NDArray[Any]: ... @@ -44,7 +43,4 @@ def show_hist( def adjust_band(band: NDArray[Any], kind: Literal["linear", "log"] | None = None) -> NDArray[Any]: ... # Misspelled upstream (`strech` instead of `stretch`); preserved as-is. -def contrast_strech( - arr: NDArray[Any], - percent_range: tuple[float, float] = (2.0, 98.0), -) -> NDArray[Any]: ... +def contrast_strech(arr: NDArray[Any], percent_range: tuple[float, float] = (2.0, 98.0)) -> NDArray[Any]: ... diff --git a/stubs/rasterio/rasterio/sample.pyi b/stubs/rasterio/rasterio/sample.pyi index 6cc7f2cb2576..d00ef2390d6f 100644 --- a/stubs/rasterio/rasterio/sample.pyi +++ b/stubs/rasterio/rasterio/sample.pyi @@ -5,10 +5,7 @@ from numpy.typing import NDArray from rasterio.io import DatasetReader def sample_gen( - dataset: DatasetReader, - xy: Iterable[tuple[float, float]], - indexes: int | Sequence[int] | None = None, - masked: bool = False, + dataset: DatasetReader, xy: Iterable[tuple[float, float]], indexes: int | Sequence[int] | None = None, masked: bool = False ) -> Iterator[NDArray[Any]]: ... # New in rasterio 1.5: sorts coordinates by x then y so callers of diff --git a/stubs/rasterio/rasterio/session.pyi b/stubs/rasterio/rasterio/session.pyi index f10a66f41c41..f41ea8e557d8 100644 --- a/stubs/rasterio/rasterio/session.pyi +++ b/stubs/rasterio/rasterio/session.pyi @@ -49,10 +49,7 @@ class AWSSession(Session): class OSSSession(Session): def __init__( - self, - oss_access_key_id: str | None = None, - oss_secret_access_key: str | None = None, - oss_endpoint: str | None = None, + self, oss_access_key_id: str | None = None, oss_secret_access_key: str | None = None, oss_endpoint: str | None = None ) -> None: ... @classmethod def hascreds(cls, config: dict[str, Any]) -> bool: ... diff --git a/stubs/rasterio/rasterio/transform.pyi b/stubs/rasterio/rasterio/transform.pyi index d39af8d9e452..9ece52ef629c 100644 --- a/stubs/rasterio/rasterio/transform.pyi +++ b/stubs/rasterio/rasterio/transform.pyi @@ -70,10 +70,7 @@ def rowcol( precision: int | None = None, **rpc_options: Any, ) -> tuple[int, int] | tuple[list[int], list[int]]: ... -def get_transformer( - transform: Affine | Sequence[GroundControlPoint] | RPC, - **rpc_options: Any, -) -> type[TransformerBase]: ... +def get_transformer(transform: Affine | Sequence[GroundControlPoint] | RPC, **rpc_options: Any) -> type[TransformerBase]: ... class TransformerBase: def __init__(self) -> None: ... @@ -84,6 +81,7 @@ class TransformerBase: zs: float | Sequence[float] | None = None, offset: _OffsetOptions = "center", ) -> tuple[float, float] | tuple[list[float], list[float]]: ... + @overload def rowcol( self, diff --git a/stubs/rasterio/rasterio/vrt.pyi b/stubs/rasterio/rasterio/vrt.pyi index 79a5ada416b9..00f0212e7504 100644 --- a/stubs/rasterio/rasterio/vrt.pyi +++ b/stubs/rasterio/rasterio/vrt.pyi @@ -8,9 +8,6 @@ from rasterio.windows import WindowMethodsMixin class WarpedVRT(WarpedVRTReaderBase, WindowMethodsMixin, TransformMethodsMixin): def __enter__(self) -> Self: ... def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None ) -> None: ... def __del__(self) -> None: ... diff --git a/stubs/rasterio/rasterio/warp.pyi b/stubs/rasterio/rasterio/warp.pyi index be6c70aac54f..da116ee9864f 100644 --- a/stubs/rasterio/rasterio/warp.pyi +++ b/stubs/rasterio/rasterio/warp.pyi @@ -17,11 +17,7 @@ _Rpcs: TypeAlias = RPC | Mapping[str, Any] SUPPORTED_RESAMPLING: Final[list[Resampling]] def transform( - src_crs: CRSInput, - dst_crs: CRSInput, - xs: ArrayLike, - ys: ArrayLike, - zs: ArrayLike | None = None, + src_crs: CRSInput, dst_crs: CRSInput, xs: ArrayLike, ys: ArrayLike, zs: ArrayLike | None = None ) -> tuple[list[float], list[float]] | tuple[list[float], list[float], list[float]]: ... # In rasterio 1.5 `antimeridian_cutting` and `antimeridian_offset` are @@ -31,11 +27,7 @@ def transform( # call sites that still pass them. @overload def transform_geom( - src_crs: CRSInput, - dst_crs: CRSInput, - geom: Mapping[str, Any] | Sequence[Mapping[str, Any]], - *, - precision: float = -1, + src_crs: CRSInput, dst_crs: CRSInput, geom: Mapping[str, Any] | Sequence[Mapping[str, Any]], *, precision: float = -1 ) -> dict[str, Any] | list[dict[str, Any]]: ... @overload @deprecated( @@ -51,14 +43,9 @@ def transform_geom( antimeridian_offset: float | None = None, precision: float = -1, ) -> dict[str, Any] | list[dict[str, Any]]: ... + def transform_bounds( - src_crs: CRSInput, - dst_crs: CRSInput, - left: float, - bottom: float, - right: float, - top: float, - densify_pts: int = 21, + src_crs: CRSInput, dst_crs: CRSInput, left: float, bottom: float, right: float, top: float, densify_pts: int = 21 ) -> tuple[float, float, float, float]: ... def reproject( source: ArrayLike | Incomplete, @@ -82,12 +69,7 @@ def reproject( src_geoloc_array: NDArray[Any] | None = None, **kwargs: Any, ) -> tuple[NDArray[Any], Affine]: ... -def aligned_target( - transform: Affine, - width: int, - height: int, - resolution: _Resolution, -) -> tuple[Affine, int, int]: ... +def aligned_target(transform: Affine, width: int, height: int, resolution: _Resolution) -> tuple[Affine, int, int]: ... def calculate_default_transform( src_crs: CRSInput, dst_crs: CRSInput, diff --git a/stubs/rasterio/rasterio/windows.pyi b/stubs/rasterio/rasterio/windows.pyi index 24b855e69014..da65bd0bcfea 100644 --- a/stubs/rasterio/rasterio/windows.pyi +++ b/stubs/rasterio/rasterio/windows.pyi @@ -15,14 +15,8 @@ class WindowMethodsMixin: def window(self, left: float, bottom: float, right: float, top: float) -> Window: ... @overload @deprecated("The `precision` parameter is unused since rasterio 1.3 and will be removed in 2.0.0.") - def window( - self, - left: float, - bottom: float, - right: float, - top: float, - precision: int | None = None, - ) -> Window: ... + def window(self, left: float, bottom: float, right: float, top: float, precision: int | None = None) -> Window: ... + def window_transform(self, window: Window) -> Affine: ... def window_bounds(self, window: Window) -> _Bounds: ... @@ -32,14 +26,9 @@ def get_data_window(arr: NDArray[Any], nodata: float | None = None) -> Window: . def union(*windows: Window) -> Window: ... def intersection(*windows: Window) -> Window: ... def intersect(*windows: Window) -> bool: ... + @overload -def from_bounds( - left: float, - bottom: float, - right: float, - top: float, - transform: Affine | None = None, -) -> Window: ... +def from_bounds(left: float, bottom: float, right: float, top: float, transform: Affine | None = None) -> Window: ... @overload @deprecated( "`height`, `width`, and `precision` on windows.from_bounds are unused since rasterio 1.3 and will be removed in 2.0.0." @@ -54,6 +43,7 @@ def from_bounds( width: int | None = None, precision: int | None = None, ) -> Window: ... + def transform(window: Window, transform: Affine) -> Affine: ... def bounds(window: Window, transform: Affine, height: int = 0, width: int = 0) -> _Bounds: ... def crop(window: Window, height: int, width: int) -> Window: ... @@ -61,10 +51,7 @@ def evaluate(window: Window, height: int, width: int, boundless: bool = False) - def shape(window: Window, height: int = -1, width: int = -1) -> tuple[int, int]: ... def window_index(window: Window, height: int = 0, width: int = 0) -> _Slices: ... def round_window_to_full_blocks( - window: Window, - block_shapes: Sequence[tuple[int, int]], - height: int = 0, - width: int = 0, + window: Window, block_shapes: Sequence[tuple[int, int]], height: int = 0, width: int = 0 ) -> Window: ... def validate_length_value(instance: object, attribute: object, value: float) -> None: ... def subdivide(window: Window, height: int, width: int) -> list[Window]: ... @@ -81,12 +68,7 @@ class Window: def toslices(self) -> _Slices: ... @classmethod def from_slices( - cls, - rows: slice | Sequence[int], - cols: slice | Sequence[int], - height: int = -1, - width: int = -1, - boundless: bool = False, + cls, rows: slice | Sequence[int], cols: slice | Sequence[int], height: int = -1, width: int = -1, boundless: bool = False ) -> Self: ... # The runtime accepts arbitrary kwargs (op, pixel_precision) for these # methods to preserve backwards compatibility while emitting deprecation From 7d2655894a33b98ac2d7dd77b8fd2871fc68e6dd Mon Sep 17 00:00:00 2001 From: Thomas Maschler Date: Mon, 8 Jun 2026 12:55:35 -0400 Subject: [PATCH 3/7] [rasterio] Drop apt/brew dependencies and prune comments rasterio ships self-contained binary wheels for every platform/Python combination typeshed CI targets (manylinux x86_64/aarch64, macOS x86_64/arm64, Windows), so no system GDAL is needed for stubtest. Removing libgdal-dev also unblocks the aggregate apt-install step: libgdal-dev on Ubuntu noble hard-depends on default-libmysqlclient-dev, whose libmysqlclient-dev provider is currently broken in the noble archive. Also strips justifying / explanatory comments throughout the stubs. --- stubs/rasterio/@tests/stubtest_allowlist.txt | 16 -------------- .../@tests/test_cases/check_dataset.py | 6 ------ .../@tests/test_cases/check_transform_geom.py | 5 ----- stubs/rasterio/METADATA.toml | 11 ---------- stubs/rasterio/rasterio/_affine_types.pyi | 5 +---- stubs/rasterio/rasterio/_base.pyi | 21 ------------------- stubs/rasterio/rasterio/_err.pyi | 2 -- stubs/rasterio/rasterio/_io.pyi | 4 ---- stubs/rasterio/rasterio/_path.pyi | 2 -- stubs/rasterio/rasterio/_warp.pyi | 5 ----- stubs/rasterio/rasterio/crs.pyi | 7 ------- stubs/rasterio/rasterio/dtypes.pyi | 3 --- stubs/rasterio/rasterio/enums.pyi | 2 -- stubs/rasterio/rasterio/env.pyi | 2 -- stubs/rasterio/rasterio/features.pyi | 3 --- stubs/rasterio/rasterio/io.pyi | 3 --- stubs/rasterio/rasterio/merge.pyi | 1 - stubs/rasterio/rasterio/path.pyi | 5 ----- stubs/rasterio/rasterio/plot.pyi | 4 ---- stubs/rasterio/rasterio/sample.pyi | 3 --- stubs/rasterio/rasterio/session.pyi | 3 --- stubs/rasterio/rasterio/transform.pyi | 11 ---------- stubs/rasterio/rasterio/warp.pyi | 7 ------- stubs/rasterio/rasterio/windows.pyi | 6 ------ 24 files changed, 1 insertion(+), 136 deletions(-) diff --git a/stubs/rasterio/@tests/stubtest_allowlist.txt b/stubs/rasterio/@tests/stubtest_allowlist.txt index f3203434f693..c7d3d9998e40 100644 --- a/stubs/rasterio/@tests/stubtest_allowlist.txt +++ b/stubs/rasterio/@tests/stubtest_allowlist.txt @@ -1,24 +1,8 @@ -# Stubtest allowlist for rasterio. -# -# Each line is a regex; matches are *not* reported by stubtest. Format mirrors -# python/typeshed so the file can move into `stubs/rasterio/@tests/` unchanged. -# Most "item present at runtime but missing from stub" cases are silenced by -# the `--ignore-missing-stub` flag (we mark the package `partial-stub = true` -# in METADATA.toml). This file lists per-symbol exceptions that aren't covered -# by that flag. - -# Stubs-only helper modules (no runtime counterpart). rasterio\._typing rasterio\._affine_types - -# Stubs-only type aliases used in signatures only. rasterio\.features\.Geometry rasterio\.merge\.MethodFunction -# Cython extension classes need `@disjoint_base` and have Cython-introspected -# parameter names that sometimes disagree with the stub. We hide these for the -# subset of private modules that still surface drift after the Public-API -# reconciliation. Users typically call positionally, so this is low-risk. rasterio\._base.* rasterio\._io.* rasterio\._env.* diff --git a/stubs/rasterio/@tests/test_cases/check_dataset.py b/stubs/rasterio/@tests/test_cases/check_dataset.py index 1564c99b8a1b..712be030d4e7 100644 --- a/stubs/rasterio/@tests/test_cases/check_dataset.py +++ b/stubs/rasterio/@tests/test_cases/check_dataset.py @@ -14,12 +14,6 @@ def check_props(reader: DatasetReader) -> None: assert_type(reader.crs, CRS) - # NOTE: `reader.transform` is typed via the stubs-only - # `rasterio._affine_types.Affine = Any` indirection until affine - # ships its own `py.typed` (v3). No `assert_type` here because the - # alias is `Any`; once affine v3 lands and the indirection swaps to - # `from affine import Affine`, an `assert_type(reader.transform, - # Affine)` line should be reinstated. assert_type(reader.bounds, BoundingBox) assert_type(reader.profile, Profile) assert_type(reader.count, int) diff --git a/stubs/rasterio/@tests/test_cases/check_transform_geom.py b/stubs/rasterio/@tests/test_cases/check_transform_geom.py index 1295d7debcaf..43f60d21c5ba 100644 --- a/stubs/rasterio/@tests/test_cases/check_transform_geom.py +++ b/stubs/rasterio/@tests/test_cases/check_transform_geom.py @@ -9,13 +9,8 @@ dst = CRS.from_epsg(3857) geom: dict[str, object] = {"type": "Point", "coordinates": [0.0, 0.0]} -# Modern overload — no deprecated kwargs. transform_geom(src, dst, geom) transform_geom(src, dst, geom, precision=2) -# Legacy overload — `antimeridian_*` kwargs are deprecated no-ops since -# GDAL 2.2. The @deprecated marker on the overload is carried in the stub; -# typeshed's regr_test does not opt into `enable_error_code = deprecated` -# so this call type-checks here, but downstream consumers see the warning. transform_geom(src, dst, geom, antimeridian_cutting=True) transform_geom(src, dst, geom, antimeridian_offset=10.0) diff --git a/stubs/rasterio/METADATA.toml b/stubs/rasterio/METADATA.toml index 9f7ffa9f7378..70670512707c 100644 --- a/stubs/rasterio/METADATA.toml +++ b/stubs/rasterio/METADATA.toml @@ -1,20 +1,9 @@ version = "1.5.*" upstream-repository = "https://github.com/rasterio/rasterio" -# rasterio 1.5 itself requires Python 3.12+, so we mirror its floor. requires-python = ">=3.12" -# `numpy` and `click` ship their own `py.typed`; listed by their PyPI runtime -# name. `affine` is referenced only through the stubs-only -# `rasterio._affine_types` indirection (Affine -> Any), so no stub or -# runtime dependency on affine is needed here. dependencies = ["numpy>=2", "click>=8"] -# Not every internal symbol is typed (notably much of the Cython extension -# layer), but the entire public API surface is covered. partial-stub = true [tool.stubtest] -# Mirror the package-level partial-stub flag — internal Cython attributes -# (`__attrs_*`, `__reduce_cython__`, etc.) are not enumerated in the stubs. ignore-missing-stub = true stubtest-dependencies = ["rasterio==1.5.*"] -apt-dependencies = ["libgdal-dev", "gdal-bin"] -brew-dependencies = ["gdal"] diff --git a/stubs/rasterio/rasterio/_affine_types.pyi b/stubs/rasterio/rasterio/_affine_types.pyi index 112557c71595..bf462c70813f 100644 --- a/stubs/rasterio/rasterio/_affine_types.pyi +++ b/stubs/rasterio/rasterio/_affine_types.pyi @@ -1,7 +1,4 @@ -# Stubs-only indirection for `affine` package types used in rasterio -# signatures. Until affine ships its own `py.typed` (planned for v3), -# `Affine` is exposed as `Any`. When affine v3 lands, replace the body -# of this module with `from affine import Affine as Affine`. +# Swap to `from affine import Affine as Affine` once affine ships `py.typed` (v3). from typing import Any, TypeAlias Affine: TypeAlias = Any diff --git a/stubs/rasterio/rasterio/_base.pyi b/stubs/rasterio/rasterio/_base.pyi index 985e8627c693..60354339fdd3 100644 --- a/stubs/rasterio/rasterio/_base.pyi +++ b/stubs/rasterio/rasterio/_base.pyi @@ -22,8 +22,6 @@ def get_dataset_driver(path: str) -> str: ... def driver_supports_mode(drivername: str, creation_mode: str) -> bool: ... def driver_can_create(drivername: str) -> bool: ... def driver_can_create_copy(drivername: str) -> bool: ... - -# Re-imported from `rasterio.transform` at runtime. def tastes_like_gdal(seq: Affine | Sequence[float]) -> bool: ... def _raster_driver_extensions() -> dict[str, str]: ... def _can_create_osr(crs: CRSInput) -> bool: ... @@ -70,47 +68,37 @@ class DatasetBase: def get_nodatavals(self) -> tuple[float | None, ...]: ... @property def nodatavals(self) -> tuple[float | None, ...]: ... - @property def nodata(self) -> float | None: ... @nodata.setter def nodata(self, value: float | None) -> None: ... - @property def mask_flag_enums(self) -> tuple[list[MaskFlags], ...]: ... - @property def crs(self) -> CRS: ... @crs.setter def crs(self, value: CRSInput) -> None: ... - @property def descriptions(self) -> tuple[str | None, ...]: ... @descriptions.setter def descriptions(self, value: Sequence[str | None]) -> None: ... - def write_transform(self, transform: Sequence[float]) -> None: ... - @property def transform(self) -> Affine: ... @transform.setter def transform(self, value: Affine) -> None: ... - @property def offsets(self) -> tuple[float, ...]: ... @offsets.setter def offsets(self, value: Sequence[float]) -> None: ... - @property def scales(self) -> tuple[float, ...]: ... @scales.setter def scales(self, value: Sequence[float]) -> None: ... - @property def units(self) -> tuple[str | None, ...]: ... @units.setter def units(self, value: Sequence[str | None]) -> None: ... - def block_window(self, bidx: int, i: int, j: int) -> Window: ... def block_size(self, bidx: int, i: int, j: int) -> int: ... def block_windows(self, bidx: int = 0) -> Iterable[tuple[tuple[int, int], Window]]: ... @@ -138,35 +126,27 @@ class DatasetBase: def tag_namespaces(self, bidx: int = 0) -> list[str]: ... def tags(self, bidx: int = 0, ns: str | None = None) -> dict[str, str]: ... def get_tag_item(self, ns: str, dm: str | None = None, bidx: int = 0, ovr: int | None = None) -> str | None: ... - @property def colorinterp(self) -> tuple[ColorInterp, ...]: ... @colorinterp.setter def colorinterp(self, value: Sequence[ColorInterp]) -> None: ... - def colormap(self, bidx: int) -> Colormap: ... def overviews(self, bidx: int) -> list[int]: ... def checksum(self, bidx: int, window: Window | None = None) -> int: ... def get_gcps(self) -> tuple[list[GroundControlPoint], CRS]: ... - @property def gcps(self) -> tuple[list[GroundControlPoint], CRS]: ... @gcps.setter def gcps(self, value: tuple[Sequence[GroundControlPoint], CRSInput]) -> None: ... - @property def rpcs(self) -> RPC | None: ... @rpcs.setter def rpcs(self, value: RPC | None) -> None: ... - @property def files(self) -> list[str]: ... -# Module-level helpers used internally by other rasterio modules. _GDAL_AT_LEAST_3_10: Final[bool] -# Re-exported numpy dtype name constants (mirrors `rasterio.dtypes`); kept for -# compatibility with code that imports them from `rasterio._base`. complex64: Final[str] complex128: Final[str] complex_int16: Final[str] @@ -174,5 +154,4 @@ float32: Final[str] float64: Final[str] int16: Final[str] -# The path-parsing helper; re-exported here for backwards compatibility. def _parse_path(path: str): ... diff --git a/stubs/rasterio/rasterio/_err.pyi b/stubs/rasterio/rasterio/_err.pyi index e3606d30aabd..84e6be115d76 100644 --- a/stubs/rasterio/rasterio/_err.pyi +++ b/stubs/rasterio/rasterio/_err.pyi @@ -10,8 +10,6 @@ class GDALError(IntEnum): fatal = 4 class CPLE_BaseError(Exception): - # Runtime instance attributes set in __init__ (modeled at class level - # to keep the stub static-type-friendly). error: int errno: int errmsg: str diff --git a/stubs/rasterio/rasterio/_io.pyi b/stubs/rasterio/rasterio/_io.pyi index 4276dd557c84..25d5392fd9e7 100644 --- a/stubs/rasterio/rasterio/_io.pyi +++ b/stubs/rasterio/rasterio/_io.pyi @@ -14,10 +14,6 @@ from rasterio.rpc import RPC def validate_resampling(resampling: Resampling) -> None: ... def virtual_file_to_buffer(filename: str) -> bytes: ... - -# `_gdal_typename`, `_get_gdal_dtype`, and `_is_complex_int` are Cython -# re-imports from `rasterio.dtypes`; declared here for stub-only callers -# that import them from `rasterio._io`. def _is_complex_int(dtype: Any) -> bool: ... def _getnpdtype(dtype: Any) -> Any: ... def _gdal_typename(dt: Any) -> str: ... diff --git a/stubs/rasterio/rasterio/_path.pyi b/stubs/rasterio/rasterio/_path.pyi index c4f4ac18507c..c3d92cf20e32 100644 --- a/stubs/rasterio/rasterio/_path.pyi +++ b/stubs/rasterio/rasterio/_path.pyi @@ -2,8 +2,6 @@ import os from typing import Any, Final, Self SCHEMES: Final[dict[str, str]] -# In rasterio 1.5 the source assigns `ARCHIVESCHEMES = set` (the bare type), -# not a populated set instance. We mirror that quirk. ARCHIVESCHEMES: Final[type[set[Any]]] CURLSCHEMES: Final[set[str]] REMOTESCHEMES: Final[set[str]] diff --git a/stubs/rasterio/rasterio/_warp.pyi b/stubs/rasterio/rasterio/_warp.pyi index c7e4e003879c..d3508f1f614b 100644 --- a/stubs/rasterio/rasterio/_warp.pyi +++ b/stubs/rasterio/rasterio/_warp.pyi @@ -67,8 +67,6 @@ def _suggested_proxy_vrt_doc( ) -> str: ... class WarpedVRTReaderBase(DatasetReaderBase): - # Public attributes documented in the rasterio.vrt API reference and set - # in __init__. src_dataset: DatasetReader src_crs: CRS src_transform: Affine | None @@ -100,9 +98,6 @@ class WarpedVRTReaderBase(DatasetReaderBase): dtype: DTypeLike | None = None, **warp_extras: Any, ) -> None: ... - # The base read() takes `boundless`; WarpedVRT.read() does not. The base - # read() takes a generic out_shape; the WarpedVRT version reorders kwargs. - # These divergences are intentional in rasterio's API. def read( # type: ignore[override] self, indexes: Indexes | None = None, diff --git a/stubs/rasterio/rasterio/crs.pyi b/stubs/rasterio/rasterio/crs.pyi index a2fdc6655dd2..4ee71c4ae66f 100644 --- a/stubs/rasterio/rasterio/crs.pyi +++ b/stubs/rasterio/rasterio/crs.pyi @@ -4,8 +4,6 @@ from typing_extensions import deprecated, disjoint_base from rasterio.enums import WktVersion -# Set of recognised PROJ parameter keys (e.g. "x_0", "lat_0", "proj"). -# Used by CRS.to_string to strip unknown keys; documented and inspectable. all_proj_keys: set[str] @disjoint_base @@ -45,15 +43,10 @@ class CRS(Mapping[str, Any]): def linear_units(self) -> str: ... @property def units_factor(self) -> tuple[str, float]: ... - # New in rasterio 1.5: lazily-computed geodetic CRS. @property def geodetic_crs(self) -> CRS | None: ... def to_string(self) -> str: ... - # In rasterio 1.5 these are bound as a static method that gets `cls` - # passed at runtime via Cython; stubtest sees them as staticmethods. def equals(self, other: CRS, ignore_axis_order: bool = False) -> bool: ... - # CRS.get drops Mapping.get's default-value parameter at runtime; this is - # a deliberate divergence from the Mapping protocol. def get(self, item: str) -> Any: ... # type: ignore[override] @staticmethod def from_epsg(code: int | str) -> CRS: ... diff --git a/stubs/rasterio/rasterio/dtypes.pyi b/stubs/rasterio/rasterio/dtypes.pyi index 99e2299ea733..16003a399610 100644 --- a/stubs/rasterio/rasterio/dtypes.pyi +++ b/stubs/rasterio/rasterio/dtypes.pyi @@ -14,7 +14,6 @@ uint32: Final[str] int32: Final[str] int64: Final[str] uint64: Final[str] -# New in rasterio 1.5 (requires GDAL 3.10+). float16: Final[str] float32: Final[str] float64: Final[str] @@ -28,8 +27,6 @@ dtype_rev: Final[dict[str | None, int]] typename_fwd: Final[dict[int, str]] typename_rev: Final[dict[str, int]] dtype_ranges: Final[dict[str, tuple[float, float]]] -# Dispatch table from rasterio dtype letter codes to numpy info classes -# (`numpy.iinfo` / `numpy.finfo`). Used internally by `in_dtype_range`. dtype_info_registry: Final[dict[str, type]] def in_dtype_range(value: float, dtype: DTypeLike) -> bool: ... diff --git a/stubs/rasterio/rasterio/enums.pyi b/stubs/rasterio/rasterio/enums.pyi index d23fd08f7ec7..6e1a2fc76a6b 100644 --- a/stubs/rasterio/rasterio/enums.pyi +++ b/stubs/rasterio/rasterio/enums.pyi @@ -28,7 +28,6 @@ class ColorInterp(IntEnum): Y = 14 Cb = 15 Cr = 16 - # Below values require GDAL 3.10+ pan = 17 coastal = 18 rededge = 19 @@ -96,7 +95,6 @@ class Interleaving(Enum): pixel = "PIXEL" line = "LINE" band = "BAND" - # tile requires GDAL 3.11+ (new in rasterio 1.5) tile = "TILE" class MaskFlags(IntEnum): diff --git a/stubs/rasterio/rasterio/env.pyi b/stubs/rasterio/rasterio/env.pyi index c98811e3f0ba..810f1f9cb374 100644 --- a/stubs/rasterio/rasterio/env.pyi +++ b/stubs/rasterio/rasterio/env.pyi @@ -37,8 +37,6 @@ class Env: session: Session | None = None, aws_unsigned: bool = False, profile_name: str | None = None, - # Defaults to Session.aws_or_dummy at runtime, but any - # Session-returning callable works. session_class: Callable[..., Session] = ..., **options: Any, ) -> None: ... diff --git a/stubs/rasterio/rasterio/features.pyi b/stubs/rasterio/rasterio/features.pyi index cf1d5910c78d..9aaa8a9ba4a7 100644 --- a/stubs/rasterio/rasterio/features.pyi +++ b/stubs/rasterio/rasterio/features.pyi @@ -10,7 +10,6 @@ from rasterio.enums import MergeAlg as MergeAlg from rasterio.io import DatasetReader from rasterio.windows import Window as Window -# Stubs-only type alias for GeoJSON-like dicts. Not exported at runtime. Geometry: TypeAlias = Mapping[str, Any] def geometry_mask( @@ -39,7 +38,6 @@ def rasterize( dst_kwds: dict[str, Any] | None = None, ) -> NDArray[Any]: ... def bounds(geometry: Geometry, north_up: bool = True, transform: Affine | None = None) -> tuple[float, float, float, float]: ... - @overload def geometry_window( dataset: DatasetReader, shapes: Iterable[Geometry], pad_x: float = 0, pad_y: float = 0, *, boundless: bool = False @@ -59,7 +57,6 @@ def geometry_window( pixel_precision: float | None = None, boundless: bool = False, ) -> Window: ... - def is_valid_geom(geom: Geometry) -> bool: ... def dataset_features( src: DatasetReader, diff --git a/stubs/rasterio/rasterio/io.pyi b/stubs/rasterio/rasterio/io.pyi index f48e5bf3e34e..c90cdd8eeb21 100644 --- a/stubs/rasterio/rasterio/io.pyi +++ b/stubs/rasterio/rasterio/io.pyi @@ -44,9 +44,6 @@ class MemoryFile(MemoryFileBase): class ZipMemoryFile(MemoryFile): def __init__(self, file_or_bytes: FileOrBytes | None = None) -> None: ... - # ZipMemoryFile.open takes `path` as a required positional arg, which - # breaks Liskov substitution with MemoryFile.open. This is intentional in - # rasterio. def open( # type: ignore[override] self, path: str, driver: str | None = None, sharing: bool = False, thread_safe: bool = False, **kwargs: Any ) -> DatasetReader: ... diff --git a/stubs/rasterio/rasterio/merge.pyi b/stubs/rasterio/rasterio/merge.pyi index 2a29936406d0..ba1c68fe307b 100644 --- a/stubs/rasterio/rasterio/merge.pyi +++ b/stubs/rasterio/rasterio/merge.pyi @@ -22,7 +22,6 @@ def copy_min(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Ar def copy_max(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... def copy_sum(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... def copy_count(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... - @overload def merge( sources: Sequence[DatasetReader | str | os.PathLike[str]], diff --git a/stubs/rasterio/rasterio/path.pyi b/stubs/rasterio/rasterio/path.pyi index 94d9630d8af0..b5e935ebfd94 100644 --- a/stubs/rasterio/rasterio/path.pyi +++ b/stubs/rasterio/rasterio/path.pyi @@ -4,11 +4,6 @@ from typing_extensions import deprecated from rasterio._path import _ParsedPath, _UnparsedPath from rasterio.errors import RasterioDeprecationWarning as RasterioDeprecationWarning -# The entire `rasterio.path` module is deprecated (the runtime emits a -# RasterioDeprecationWarning on import) and will be removed in a future -# rasterio release. Each re-export below is marked @deprecated so type -# checkers flag every call site, not just the import line. - ParsedPath: TypeAlias = _ParsedPath UnparsedPath: TypeAlias = _UnparsedPath diff --git a/stubs/rasterio/rasterio/plot.pyi b/stubs/rasterio/rasterio/plot.pyi index aafc07ccd5dc..7d7f27c0a535 100644 --- a/stubs/rasterio/rasterio/plot.pyi +++ b/stubs/rasterio/rasterio/plot.pyi @@ -15,12 +15,10 @@ def show( with_bounds: bool = True, contour: bool = False, contour_label_kws: Mapping[str, Any] | None = None, - # New in rasterio 1.5: rgb composite band selection. indexes: Sequence[int] | None = None, ax: Any | None = None, title: str | None = None, transform: Affine | None = None, - # New in rasterio 1.5: histogram-stretch percentile range. percent_range: tuple[float, float] | None = None, adjust: bool = True, **kwargs: Any, @@ -41,6 +39,4 @@ def show_hist( **kwargs: Any, ) -> None: ... def adjust_band(band: NDArray[Any], kind: Literal["linear", "log"] | None = None) -> NDArray[Any]: ... - -# Misspelled upstream (`strech` instead of `stretch`); preserved as-is. def contrast_strech(arr: NDArray[Any], percent_range: tuple[float, float] = (2.0, 98.0)) -> NDArray[Any]: ... diff --git a/stubs/rasterio/rasterio/sample.pyi b/stubs/rasterio/rasterio/sample.pyi index d00ef2390d6f..8c87ecae7fcf 100644 --- a/stubs/rasterio/rasterio/sample.pyi +++ b/stubs/rasterio/rasterio/sample.pyi @@ -7,7 +7,4 @@ from rasterio.io import DatasetReader def sample_gen( dataset: DatasetReader, xy: Iterable[tuple[float, float]], indexes: int | Sequence[int] | None = None, masked: bool = False ) -> Iterator[NDArray[Any]]: ... - -# New in rasterio 1.5: sorts coordinates by x then y so callers of -# sample_gen can hint better dataset block access patterns. def sort_xy(xy: Iterable[tuple[float, float]]) -> list[tuple[float, float]]: ... diff --git a/stubs/rasterio/rasterio/session.pyi b/stubs/rasterio/rasterio/session.pyi index f41ea8e557d8..76ab6ea93eb2 100644 --- a/stubs/rasterio/rasterio/session.pyi +++ b/stubs/rasterio/rasterio/session.pyi @@ -1,6 +1,5 @@ from typing import Any -# CPLTestBool equivalent. Public utility re-exported from rasterio.session. def parse_bool(v: bool | str | int) -> bool: ... class Session: @@ -84,8 +83,6 @@ class SwiftSession(Session): class AzureSession(Session): unsigned: bool storage_account: str | None - # Expanded in rasterio 1.5: added access_token, sas_token, tenant_id, - # client_id, federated_token_file, and authority_host parameters. def __init__( self, azure_storage_connection_string: str | None = None, diff --git a/stubs/rasterio/rasterio/transform.pyi b/stubs/rasterio/rasterio/transform.pyi index 9ece52ef629c..b9d360c3628b 100644 --- a/stubs/rasterio/rasterio/transform.pyi +++ b/stubs/rasterio/rasterio/transform.pyi @@ -26,12 +26,6 @@ class TransformMethodsMixin: transform_method: TransformMethod = ..., **rpc_options: Any, ) -> tuple[float, float] | tuple[list[float], list[float]]: ... - # NOTE: `precision=` is deprecated since rasterio 1.3 and silently - # ignored at runtime (a DeprecationWarning is emitted). We do not - # express this with @deprecated overloads here because `**rpc_options` - # would swallow the deprecated kwarg in the modern overload, defeating - # the overload resolution. Type checkers can therefore not flag - # `precision=` callers; the runtime warning is the only signal. def index( self, x: float | Sequence[float], @@ -57,10 +51,6 @@ def xy( offset: _OffsetOptions = "center", **rpc_options: Any, ) -> tuple[float, float] | tuple[list[float], list[float]]: ... - -# NOTE: `precision=` is deprecated since rasterio 1.3 and a no-op (runtime -# emits a DeprecationWarning). Not expressed via @deprecated overload here -# because `**rpc_options` would swallow it in the modern overload. def rowcol( transform: Affine | Sequence[GroundControlPoint] | RPC, xs: float | Sequence[float], @@ -81,7 +71,6 @@ class TransformerBase: zs: float | Sequence[float] | None = None, offset: _OffsetOptions = "center", ) -> tuple[float, float] | tuple[list[float], list[float]]: ... - @overload def rowcol( self, diff --git a/stubs/rasterio/rasterio/warp.pyi b/stubs/rasterio/rasterio/warp.pyi index da116ee9864f..ae3e6d9f56e9 100644 --- a/stubs/rasterio/rasterio/warp.pyi +++ b/stubs/rasterio/rasterio/warp.pyi @@ -19,12 +19,6 @@ SUPPORTED_RESAMPLING: Final[list[Resampling]] def transform( src_crs: CRSInput, dst_crs: CRSInput, xs: ArrayLike, ys: ArrayLike, zs: ArrayLike | None = None ) -> tuple[list[float], list[float]] | tuple[list[float], list[float], list[float]]: ... - -# In rasterio 1.5 `antimeridian_cutting` and `antimeridian_offset` are -# deprecated (they have been no-ops since GDAL 2.2). The modern overload -# accepts only `precision`; the legacy overload accepts the antimeridian -# kwargs and is marked @deprecated so type checkers surface a warning at -# call sites that still pass them. @overload def transform_geom( src_crs: CRSInput, dst_crs: CRSInput, geom: Mapping[str, Any] | Sequence[Mapping[str, Any]], *, precision: float = -1 @@ -43,7 +37,6 @@ def transform_geom( antimeridian_offset: float | None = None, precision: float = -1, ) -> dict[str, Any] | list[dict[str, Any]]: ... - def transform_bounds( src_crs: CRSInput, dst_crs: CRSInput, left: float, bottom: float, right: float, top: float, densify_pts: int = 21 ) -> tuple[float, float, float, float]: ... diff --git a/stubs/rasterio/rasterio/windows.pyi b/stubs/rasterio/rasterio/windows.pyi index da65bd0bcfea..f9fef7bfc609 100644 --- a/stubs/rasterio/rasterio/windows.pyi +++ b/stubs/rasterio/rasterio/windows.pyi @@ -16,7 +16,6 @@ class WindowMethodsMixin: @overload @deprecated("The `precision` parameter is unused since rasterio 1.3 and will be removed in 2.0.0.") def window(self, left: float, bottom: float, right: float, top: float, precision: int | None = None) -> Window: ... - def window_transform(self, window: Window) -> Affine: ... def window_bounds(self, window: Window) -> _Bounds: ... @@ -26,7 +25,6 @@ def get_data_window(arr: NDArray[Any], nodata: float | None = None) -> Window: . def union(*windows: Window) -> Window: ... def intersection(*windows: Window) -> Window: ... def intersect(*windows: Window) -> bool: ... - @overload def from_bounds(left: float, bottom: float, right: float, top: float, transform: Affine | None = None) -> Window: ... @overload @@ -43,7 +41,6 @@ def from_bounds( width: int | None = None, precision: int | None = None, ) -> Window: ... - def transform(window: Window, transform: Affine) -> Affine: ... def bounds(window: Window, transform: Affine, height: int = 0, width: int = 0) -> _Bounds: ... def crop(window: Window, height: int, width: int) -> Window: ... @@ -70,9 +67,6 @@ class Window: def from_slices( cls, rows: slice | Sequence[int], cols: slice | Sequence[int], height: int = -1, width: int = -1, boundless: bool = False ) -> Self: ... - # The runtime accepts arbitrary kwargs (op, pixel_precision) for these - # methods to preserve backwards compatibility while emitting deprecation - # warnings. We type them as **kwds to match. def round_lengths(self, **kwds: Any) -> Window: ... @deprecated("Window.round_shape is deprecated and will be removed in Rasterio 2.0.0; use round_lengths instead.") def round_shape(self, **kwds: Any) -> Window: ... From 50acf5d055775b1a91ef5a0f11a4f64bfecc1e30 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 8 Jun 2026 16:57:46 +0000 Subject: [PATCH 4/7] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stubs/rasterio/rasterio/_base.pyi | 15 +++++++++++++++ stubs/rasterio/rasterio/features.pyi | 2 ++ stubs/rasterio/rasterio/merge.pyi | 1 + stubs/rasterio/rasterio/transform.pyi | 1 + stubs/rasterio/rasterio/warp.pyi | 2 ++ stubs/rasterio/rasterio/windows.pyi | 3 +++ 6 files changed, 24 insertions(+) diff --git a/stubs/rasterio/rasterio/_base.pyi b/stubs/rasterio/rasterio/_base.pyi index 60354339fdd3..41ac756e8736 100644 --- a/stubs/rasterio/rasterio/_base.pyi +++ b/stubs/rasterio/rasterio/_base.pyi @@ -68,37 +68,47 @@ class DatasetBase: def get_nodatavals(self) -> tuple[float | None, ...]: ... @property def nodatavals(self) -> tuple[float | None, ...]: ... + @property def nodata(self) -> float | None: ... @nodata.setter def nodata(self, value: float | None) -> None: ... + @property def mask_flag_enums(self) -> tuple[list[MaskFlags], ...]: ... + @property def crs(self) -> CRS: ... @crs.setter def crs(self, value: CRSInput) -> None: ... + @property def descriptions(self) -> tuple[str | None, ...]: ... @descriptions.setter def descriptions(self, value: Sequence[str | None]) -> None: ... + def write_transform(self, transform: Sequence[float]) -> None: ... + @property def transform(self) -> Affine: ... @transform.setter def transform(self, value: Affine) -> None: ... + @property def offsets(self) -> tuple[float, ...]: ... @offsets.setter def offsets(self, value: Sequence[float]) -> None: ... + @property def scales(self) -> tuple[float, ...]: ... @scales.setter def scales(self, value: Sequence[float]) -> None: ... + @property def units(self) -> tuple[str | None, ...]: ... @units.setter def units(self, value: Sequence[str | None]) -> None: ... + def block_window(self, bidx: int, i: int, j: int) -> Window: ... def block_size(self, bidx: int, i: int, j: int) -> int: ... def block_windows(self, bidx: int = 0) -> Iterable[tuple[tuple[int, int], Window]]: ... @@ -126,22 +136,27 @@ class DatasetBase: def tag_namespaces(self, bidx: int = 0) -> list[str]: ... def tags(self, bidx: int = 0, ns: str | None = None) -> dict[str, str]: ... def get_tag_item(self, ns: str, dm: str | None = None, bidx: int = 0, ovr: int | None = None) -> str | None: ... + @property def colorinterp(self) -> tuple[ColorInterp, ...]: ... @colorinterp.setter def colorinterp(self, value: Sequence[ColorInterp]) -> None: ... + def colormap(self, bidx: int) -> Colormap: ... def overviews(self, bidx: int) -> list[int]: ... def checksum(self, bidx: int, window: Window | None = None) -> int: ... def get_gcps(self) -> tuple[list[GroundControlPoint], CRS]: ... + @property def gcps(self) -> tuple[list[GroundControlPoint], CRS]: ... @gcps.setter def gcps(self, value: tuple[Sequence[GroundControlPoint], CRSInput]) -> None: ... + @property def rpcs(self) -> RPC | None: ... @rpcs.setter def rpcs(self, value: RPC | None) -> None: ... + @property def files(self) -> list[str]: ... diff --git a/stubs/rasterio/rasterio/features.pyi b/stubs/rasterio/rasterio/features.pyi index 9aaa8a9ba4a7..4cd4a7fac61c 100644 --- a/stubs/rasterio/rasterio/features.pyi +++ b/stubs/rasterio/rasterio/features.pyi @@ -38,6 +38,7 @@ def rasterize( dst_kwds: dict[str, Any] | None = None, ) -> NDArray[Any]: ... def bounds(geometry: Geometry, north_up: bool = True, transform: Affine | None = None) -> tuple[float, float, float, float]: ... + @overload def geometry_window( dataset: DatasetReader, shapes: Iterable[Geometry], pad_x: float = 0, pad_y: float = 0, *, boundless: bool = False @@ -57,6 +58,7 @@ def geometry_window( pixel_precision: float | None = None, boundless: bool = False, ) -> Window: ... + def is_valid_geom(geom: Geometry) -> bool: ... def dataset_features( src: DatasetReader, diff --git a/stubs/rasterio/rasterio/merge.pyi b/stubs/rasterio/rasterio/merge.pyi index ba1c68fe307b..2a29936406d0 100644 --- a/stubs/rasterio/rasterio/merge.pyi +++ b/stubs/rasterio/rasterio/merge.pyi @@ -22,6 +22,7 @@ def copy_min(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Ar def copy_max(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... def copy_sum(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... def copy_count(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... + @overload def merge( sources: Sequence[DatasetReader | str | os.PathLike[str]], diff --git a/stubs/rasterio/rasterio/transform.pyi b/stubs/rasterio/rasterio/transform.pyi index b9d360c3628b..98e32e6e9c5e 100644 --- a/stubs/rasterio/rasterio/transform.pyi +++ b/stubs/rasterio/rasterio/transform.pyi @@ -71,6 +71,7 @@ class TransformerBase: zs: float | Sequence[float] | None = None, offset: _OffsetOptions = "center", ) -> tuple[float, float] | tuple[list[float], list[float]]: ... + @overload def rowcol( self, diff --git a/stubs/rasterio/rasterio/warp.pyi b/stubs/rasterio/rasterio/warp.pyi index ae3e6d9f56e9..c6844532963e 100644 --- a/stubs/rasterio/rasterio/warp.pyi +++ b/stubs/rasterio/rasterio/warp.pyi @@ -19,6 +19,7 @@ SUPPORTED_RESAMPLING: Final[list[Resampling]] def transform( src_crs: CRSInput, dst_crs: CRSInput, xs: ArrayLike, ys: ArrayLike, zs: ArrayLike | None = None ) -> tuple[list[float], list[float]] | tuple[list[float], list[float], list[float]]: ... + @overload def transform_geom( src_crs: CRSInput, dst_crs: CRSInput, geom: Mapping[str, Any] | Sequence[Mapping[str, Any]], *, precision: float = -1 @@ -37,6 +38,7 @@ def transform_geom( antimeridian_offset: float | None = None, precision: float = -1, ) -> dict[str, Any] | list[dict[str, Any]]: ... + def transform_bounds( src_crs: CRSInput, dst_crs: CRSInput, left: float, bottom: float, right: float, top: float, densify_pts: int = 21 ) -> tuple[float, float, float, float]: ... diff --git a/stubs/rasterio/rasterio/windows.pyi b/stubs/rasterio/rasterio/windows.pyi index f9fef7bfc609..db7ea49e8272 100644 --- a/stubs/rasterio/rasterio/windows.pyi +++ b/stubs/rasterio/rasterio/windows.pyi @@ -16,6 +16,7 @@ class WindowMethodsMixin: @overload @deprecated("The `precision` parameter is unused since rasterio 1.3 and will be removed in 2.0.0.") def window(self, left: float, bottom: float, right: float, top: float, precision: int | None = None) -> Window: ... + def window_transform(self, window: Window) -> Affine: ... def window_bounds(self, window: Window) -> _Bounds: ... @@ -25,6 +26,7 @@ def get_data_window(arr: NDArray[Any], nodata: float | None = None) -> Window: . def union(*windows: Window) -> Window: ... def intersection(*windows: Window) -> Window: ... def intersect(*windows: Window) -> bool: ... + @overload def from_bounds(left: float, bottom: float, right: float, top: float, transform: Affine | None = None) -> Window: ... @overload @@ -41,6 +43,7 @@ def from_bounds( width: int | None = None, precision: int | None = None, ) -> Window: ... + def transform(window: Window, transform: Affine) -> Affine: ... def bounds(window: Window, transform: Affine, height: int = 0, width: int = 0) -> _Bounds: ... def crop(window: Window, height: int, width: int) -> Window: ... From 46cb66547eaaf8ac6a628c6c78d47ac31d84c873 Mon Sep 17 00:00:00 2001 From: Thomas Maschler Date: Mon, 8 Jun 2026 13:02:13 -0400 Subject: [PATCH 5/7] [rasterio] Fix pyright testcase failures * check_open.py: rename `_opaque_mode` -> `check_opaque_mode` so the helper is no longer flagged as `reportUnusedFunction`. * check_transform_geom.py: mark the two intentional deprecated-overload calls with `# pyright: ignore[reportDeprecated]` (they exist to exercise the `@deprecated` overload routing). --- stubs/rasterio/@tests/test_cases/check_open.py | 4 +--- stubs/rasterio/@tests/test_cases/check_transform_geom.py | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/stubs/rasterio/@tests/test_cases/check_open.py b/stubs/rasterio/@tests/test_cases/check_open.py index 2517b719168a..dba7cd7123d5 100644 --- a/stubs/rasterio/@tests/test_cases/check_open.py +++ b/stubs/rasterio/@tests/test_cases/check_open.py @@ -17,10 +17,8 @@ assert_type(rasterio.open("foo.tif", "w+"), DatasetWriter) -def _opaque_mode(mode: str) -> None: - # When `mode` is opaque str, the union overload is picked. +def check_opaque_mode(mode: str) -> None: assert_type(rasterio.open("foo.tif", mode), DatasetReader | DatasetWriter) -# An int path is not a valid `fp`; the overload check rejects it. rasterio.open(123) # type: ignore[call-overload] diff --git a/stubs/rasterio/@tests/test_cases/check_transform_geom.py b/stubs/rasterio/@tests/test_cases/check_transform_geom.py index 43f60d21c5ba..c93dc592ced6 100644 --- a/stubs/rasterio/@tests/test_cases/check_transform_geom.py +++ b/stubs/rasterio/@tests/test_cases/check_transform_geom.py @@ -12,5 +12,5 @@ transform_geom(src, dst, geom) transform_geom(src, dst, geom, precision=2) -transform_geom(src, dst, geom, antimeridian_cutting=True) -transform_geom(src, dst, geom, antimeridian_offset=10.0) +transform_geom(src, dst, geom, antimeridian_cutting=True) # pyright: ignore[reportDeprecated] +transform_geom(src, dst, geom, antimeridian_offset=10.0) # pyright: ignore[reportDeprecated] From 0f35ce51522667d77228b1259b2d3dda7545bde5 Mon Sep 17 00:00:00 2001 From: Thomas Maschler Date: Mon, 8 Jun 2026 13:15:50 -0400 Subject: [PATCH 6/7] [rasterio] Annotate _parse_path return for stricter pyright `pyrightconfig.stricter.json` (which checks rasterio because the package isn't on the exclude list) flagged `_base._parse_path(path: str): ...` for an unknown return type (`reportUnknownParameterType`) on every Darwin/Windows matrix combo. The runtime forwards to `rasterio._path._parse_path`; mirror its return annotation here. Also apply ruff format to drop the blank lines between adjacent class members (typeshed style; was getting re-applied by pre-commit-ci). --- stubs/rasterio/rasterio/_base.pyi | 17 +---------------- stubs/rasterio/rasterio/features.pyi | 2 -- stubs/rasterio/rasterio/merge.pyi | 1 - stubs/rasterio/rasterio/transform.pyi | 1 - stubs/rasterio/rasterio/warp.pyi | 2 -- stubs/rasterio/rasterio/windows.pyi | 3 --- 6 files changed, 1 insertion(+), 25 deletions(-) diff --git a/stubs/rasterio/rasterio/_base.pyi b/stubs/rasterio/rasterio/_base.pyi index 41ac756e8736..a86e01d65090 100644 --- a/stubs/rasterio/rasterio/_base.pyi +++ b/stubs/rasterio/rasterio/_base.pyi @@ -68,47 +68,37 @@ class DatasetBase: def get_nodatavals(self) -> tuple[float | None, ...]: ... @property def nodatavals(self) -> tuple[float | None, ...]: ... - @property def nodata(self) -> float | None: ... @nodata.setter def nodata(self, value: float | None) -> None: ... - @property def mask_flag_enums(self) -> tuple[list[MaskFlags], ...]: ... - @property def crs(self) -> CRS: ... @crs.setter def crs(self, value: CRSInput) -> None: ... - @property def descriptions(self) -> tuple[str | None, ...]: ... @descriptions.setter def descriptions(self, value: Sequence[str | None]) -> None: ... - def write_transform(self, transform: Sequence[float]) -> None: ... - @property def transform(self) -> Affine: ... @transform.setter def transform(self, value: Affine) -> None: ... - @property def offsets(self) -> tuple[float, ...]: ... @offsets.setter def offsets(self, value: Sequence[float]) -> None: ... - @property def scales(self) -> tuple[float, ...]: ... @scales.setter def scales(self, value: Sequence[float]) -> None: ... - @property def units(self) -> tuple[str | None, ...]: ... @units.setter def units(self, value: Sequence[str | None]) -> None: ... - def block_window(self, bidx: int, i: int, j: int) -> Window: ... def block_size(self, bidx: int, i: int, j: int) -> int: ... def block_windows(self, bidx: int = 0) -> Iterable[tuple[tuple[int, int], Window]]: ... @@ -136,27 +126,22 @@ class DatasetBase: def tag_namespaces(self, bidx: int = 0) -> list[str]: ... def tags(self, bidx: int = 0, ns: str | None = None) -> dict[str, str]: ... def get_tag_item(self, ns: str, dm: str | None = None, bidx: int = 0, ovr: int | None = None) -> str | None: ... - @property def colorinterp(self) -> tuple[ColorInterp, ...]: ... @colorinterp.setter def colorinterp(self, value: Sequence[ColorInterp]) -> None: ... - def colormap(self, bidx: int) -> Colormap: ... def overviews(self, bidx: int) -> list[int]: ... def checksum(self, bidx: int, window: Window | None = None) -> int: ... def get_gcps(self) -> tuple[list[GroundControlPoint], CRS]: ... - @property def gcps(self) -> tuple[list[GroundControlPoint], CRS]: ... @gcps.setter def gcps(self, value: tuple[Sequence[GroundControlPoint], CRSInput]) -> None: ... - @property def rpcs(self) -> RPC | None: ... @rpcs.setter def rpcs(self, value: RPC | None) -> None: ... - @property def files(self) -> list[str]: ... @@ -169,4 +154,4 @@ float32: Final[str] float64: Final[str] int16: Final[str] -def _parse_path(path: str): ... +def _parse_path(path: str) -> _ParsedPath | _UnparsedPath: ... diff --git a/stubs/rasterio/rasterio/features.pyi b/stubs/rasterio/rasterio/features.pyi index 4cd4a7fac61c..9aaa8a9ba4a7 100644 --- a/stubs/rasterio/rasterio/features.pyi +++ b/stubs/rasterio/rasterio/features.pyi @@ -38,7 +38,6 @@ def rasterize( dst_kwds: dict[str, Any] | None = None, ) -> NDArray[Any]: ... def bounds(geometry: Geometry, north_up: bool = True, transform: Affine | None = None) -> tuple[float, float, float, float]: ... - @overload def geometry_window( dataset: DatasetReader, shapes: Iterable[Geometry], pad_x: float = 0, pad_y: float = 0, *, boundless: bool = False @@ -58,7 +57,6 @@ def geometry_window( pixel_precision: float | None = None, boundless: bool = False, ) -> Window: ... - def is_valid_geom(geom: Geometry) -> bool: ... def dataset_features( src: DatasetReader, diff --git a/stubs/rasterio/rasterio/merge.pyi b/stubs/rasterio/rasterio/merge.pyi index 2a29936406d0..ba1c68fe307b 100644 --- a/stubs/rasterio/rasterio/merge.pyi +++ b/stubs/rasterio/rasterio/merge.pyi @@ -22,7 +22,6 @@ def copy_min(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Ar def copy_max(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... def copy_sum(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... def copy_count(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... - @overload def merge( sources: Sequence[DatasetReader | str | os.PathLike[str]], diff --git a/stubs/rasterio/rasterio/transform.pyi b/stubs/rasterio/rasterio/transform.pyi index 98e32e6e9c5e..b9d360c3628b 100644 --- a/stubs/rasterio/rasterio/transform.pyi +++ b/stubs/rasterio/rasterio/transform.pyi @@ -71,7 +71,6 @@ class TransformerBase: zs: float | Sequence[float] | None = None, offset: _OffsetOptions = "center", ) -> tuple[float, float] | tuple[list[float], list[float]]: ... - @overload def rowcol( self, diff --git a/stubs/rasterio/rasterio/warp.pyi b/stubs/rasterio/rasterio/warp.pyi index c6844532963e..ae3e6d9f56e9 100644 --- a/stubs/rasterio/rasterio/warp.pyi +++ b/stubs/rasterio/rasterio/warp.pyi @@ -19,7 +19,6 @@ SUPPORTED_RESAMPLING: Final[list[Resampling]] def transform( src_crs: CRSInput, dst_crs: CRSInput, xs: ArrayLike, ys: ArrayLike, zs: ArrayLike | None = None ) -> tuple[list[float], list[float]] | tuple[list[float], list[float], list[float]]: ... - @overload def transform_geom( src_crs: CRSInput, dst_crs: CRSInput, geom: Mapping[str, Any] | Sequence[Mapping[str, Any]], *, precision: float = -1 @@ -38,7 +37,6 @@ def transform_geom( antimeridian_offset: float | None = None, precision: float = -1, ) -> dict[str, Any] | list[dict[str, Any]]: ... - def transform_bounds( src_crs: CRSInput, dst_crs: CRSInput, left: float, bottom: float, right: float, top: float, densify_pts: int = 21 ) -> tuple[float, float, float, float]: ... diff --git a/stubs/rasterio/rasterio/windows.pyi b/stubs/rasterio/rasterio/windows.pyi index db7ea49e8272..f9fef7bfc609 100644 --- a/stubs/rasterio/rasterio/windows.pyi +++ b/stubs/rasterio/rasterio/windows.pyi @@ -16,7 +16,6 @@ class WindowMethodsMixin: @overload @deprecated("The `precision` parameter is unused since rasterio 1.3 and will be removed in 2.0.0.") def window(self, left: float, bottom: float, right: float, top: float, precision: int | None = None) -> Window: ... - def window_transform(self, window: Window) -> Affine: ... def window_bounds(self, window: Window) -> _Bounds: ... @@ -26,7 +25,6 @@ def get_data_window(arr: NDArray[Any], nodata: float | None = None) -> Window: . def union(*windows: Window) -> Window: ... def intersection(*windows: Window) -> Window: ... def intersect(*windows: Window) -> bool: ... - @overload def from_bounds(left: float, bottom: float, right: float, top: float, transform: Affine | None = None) -> Window: ... @overload @@ -43,7 +41,6 @@ def from_bounds( width: int | None = None, precision: int | None = None, ) -> Window: ... - def transform(window: Window, transform: Affine) -> Affine: ... def bounds(window: Window, transform: Affine, height: int = 0, width: int = 0) -> _Bounds: ... def crop(window: Window, height: int, width: int) -> Window: ... From 2cc3635db06afcc013d6e8cd7b6c7412ceaa7b55 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 8 Jun 2026 17:17:46 +0000 Subject: [PATCH 7/7] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stubs/rasterio/rasterio/_base.pyi | 15 +++++++++++++++ stubs/rasterio/rasterio/features.pyi | 2 ++ stubs/rasterio/rasterio/merge.pyi | 1 + stubs/rasterio/rasterio/transform.pyi | 1 + stubs/rasterio/rasterio/warp.pyi | 2 ++ stubs/rasterio/rasterio/windows.pyi | 3 +++ 6 files changed, 24 insertions(+) diff --git a/stubs/rasterio/rasterio/_base.pyi b/stubs/rasterio/rasterio/_base.pyi index a86e01d65090..b3a76d4e3cf2 100644 --- a/stubs/rasterio/rasterio/_base.pyi +++ b/stubs/rasterio/rasterio/_base.pyi @@ -68,37 +68,47 @@ class DatasetBase: def get_nodatavals(self) -> tuple[float | None, ...]: ... @property def nodatavals(self) -> tuple[float | None, ...]: ... + @property def nodata(self) -> float | None: ... @nodata.setter def nodata(self, value: float | None) -> None: ... + @property def mask_flag_enums(self) -> tuple[list[MaskFlags], ...]: ... + @property def crs(self) -> CRS: ... @crs.setter def crs(self, value: CRSInput) -> None: ... + @property def descriptions(self) -> tuple[str | None, ...]: ... @descriptions.setter def descriptions(self, value: Sequence[str | None]) -> None: ... + def write_transform(self, transform: Sequence[float]) -> None: ... + @property def transform(self) -> Affine: ... @transform.setter def transform(self, value: Affine) -> None: ... + @property def offsets(self) -> tuple[float, ...]: ... @offsets.setter def offsets(self, value: Sequence[float]) -> None: ... + @property def scales(self) -> tuple[float, ...]: ... @scales.setter def scales(self, value: Sequence[float]) -> None: ... + @property def units(self) -> tuple[str | None, ...]: ... @units.setter def units(self, value: Sequence[str | None]) -> None: ... + def block_window(self, bidx: int, i: int, j: int) -> Window: ... def block_size(self, bidx: int, i: int, j: int) -> int: ... def block_windows(self, bidx: int = 0) -> Iterable[tuple[tuple[int, int], Window]]: ... @@ -126,22 +136,27 @@ class DatasetBase: def tag_namespaces(self, bidx: int = 0) -> list[str]: ... def tags(self, bidx: int = 0, ns: str | None = None) -> dict[str, str]: ... def get_tag_item(self, ns: str, dm: str | None = None, bidx: int = 0, ovr: int | None = None) -> str | None: ... + @property def colorinterp(self) -> tuple[ColorInterp, ...]: ... @colorinterp.setter def colorinterp(self, value: Sequence[ColorInterp]) -> None: ... + def colormap(self, bidx: int) -> Colormap: ... def overviews(self, bidx: int) -> list[int]: ... def checksum(self, bidx: int, window: Window | None = None) -> int: ... def get_gcps(self) -> tuple[list[GroundControlPoint], CRS]: ... + @property def gcps(self) -> tuple[list[GroundControlPoint], CRS]: ... @gcps.setter def gcps(self, value: tuple[Sequence[GroundControlPoint], CRSInput]) -> None: ... + @property def rpcs(self) -> RPC | None: ... @rpcs.setter def rpcs(self, value: RPC | None) -> None: ... + @property def files(self) -> list[str]: ... diff --git a/stubs/rasterio/rasterio/features.pyi b/stubs/rasterio/rasterio/features.pyi index 9aaa8a9ba4a7..4cd4a7fac61c 100644 --- a/stubs/rasterio/rasterio/features.pyi +++ b/stubs/rasterio/rasterio/features.pyi @@ -38,6 +38,7 @@ def rasterize( dst_kwds: dict[str, Any] | None = None, ) -> NDArray[Any]: ... def bounds(geometry: Geometry, north_up: bool = True, transform: Affine | None = None) -> tuple[float, float, float, float]: ... + @overload def geometry_window( dataset: DatasetReader, shapes: Iterable[Geometry], pad_x: float = 0, pad_y: float = 0, *, boundless: bool = False @@ -57,6 +58,7 @@ def geometry_window( pixel_precision: float | None = None, boundless: bool = False, ) -> Window: ... + def is_valid_geom(geom: Geometry) -> bool: ... def dataset_features( src: DatasetReader, diff --git a/stubs/rasterio/rasterio/merge.pyi b/stubs/rasterio/rasterio/merge.pyi index ba1c68fe307b..2a29936406d0 100644 --- a/stubs/rasterio/rasterio/merge.pyi +++ b/stubs/rasterio/rasterio/merge.pyi @@ -22,6 +22,7 @@ def copy_min(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Ar def copy_max(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... def copy_sum(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... def copy_count(merged_data: _Arr, new_data: _Arr, merged_mask: _Arr, new_mask: _Arr, **kwargs: Any) -> None: ... + @overload def merge( sources: Sequence[DatasetReader | str | os.PathLike[str]], diff --git a/stubs/rasterio/rasterio/transform.pyi b/stubs/rasterio/rasterio/transform.pyi index b9d360c3628b..98e32e6e9c5e 100644 --- a/stubs/rasterio/rasterio/transform.pyi +++ b/stubs/rasterio/rasterio/transform.pyi @@ -71,6 +71,7 @@ class TransformerBase: zs: float | Sequence[float] | None = None, offset: _OffsetOptions = "center", ) -> tuple[float, float] | tuple[list[float], list[float]]: ... + @overload def rowcol( self, diff --git a/stubs/rasterio/rasterio/warp.pyi b/stubs/rasterio/rasterio/warp.pyi index ae3e6d9f56e9..c6844532963e 100644 --- a/stubs/rasterio/rasterio/warp.pyi +++ b/stubs/rasterio/rasterio/warp.pyi @@ -19,6 +19,7 @@ SUPPORTED_RESAMPLING: Final[list[Resampling]] def transform( src_crs: CRSInput, dst_crs: CRSInput, xs: ArrayLike, ys: ArrayLike, zs: ArrayLike | None = None ) -> tuple[list[float], list[float]] | tuple[list[float], list[float], list[float]]: ... + @overload def transform_geom( src_crs: CRSInput, dst_crs: CRSInput, geom: Mapping[str, Any] | Sequence[Mapping[str, Any]], *, precision: float = -1 @@ -37,6 +38,7 @@ def transform_geom( antimeridian_offset: float | None = None, precision: float = -1, ) -> dict[str, Any] | list[dict[str, Any]]: ... + def transform_bounds( src_crs: CRSInput, dst_crs: CRSInput, left: float, bottom: float, right: float, top: float, densify_pts: int = 21 ) -> tuple[float, float, float, float]: ... diff --git a/stubs/rasterio/rasterio/windows.pyi b/stubs/rasterio/rasterio/windows.pyi index f9fef7bfc609..db7ea49e8272 100644 --- a/stubs/rasterio/rasterio/windows.pyi +++ b/stubs/rasterio/rasterio/windows.pyi @@ -16,6 +16,7 @@ class WindowMethodsMixin: @overload @deprecated("The `precision` parameter is unused since rasterio 1.3 and will be removed in 2.0.0.") def window(self, left: float, bottom: float, right: float, top: float, precision: int | None = None) -> Window: ... + def window_transform(self, window: Window) -> Affine: ... def window_bounds(self, window: Window) -> _Bounds: ... @@ -25,6 +26,7 @@ def get_data_window(arr: NDArray[Any], nodata: float | None = None) -> Window: . def union(*windows: Window) -> Window: ... def intersection(*windows: Window) -> Window: ... def intersect(*windows: Window) -> bool: ... + @overload def from_bounds(left: float, bottom: float, right: float, top: float, transform: Affine | None = None) -> Window: ... @overload @@ -41,6 +43,7 @@ def from_bounds( width: int | None = None, precision: int | None = None, ) -> Window: ... + def transform(window: Window, transform: Affine) -> Affine: ... def bounds(window: Window, transform: Affine, height: int = 0, width: int = 0) -> _Bounds: ... def crop(window: Window, height: int, width: int) -> Window: ...