diff --git a/stubs/geopandas/@tests/stubtest_allowlist.txt b/stubs/geopandas/@tests/stubtest_allowlist.txt index c70c8a84ee96..8b1d55baf177 100644 --- a/stubs/geopandas/@tests/stubtest_allowlist.txt +++ b/stubs/geopandas/@tests/stubtest_allowlist.txt @@ -14,10 +14,6 @@ geopandas\.(geodataframe\.)?GeoDataFrame\.plot geopandas\.io\._geoarrow geopandas\._exports -# Not present in stub OK (do not work at runtime, to be removed from geopandas) -geopandas\.(geoseries\.)?GeoSeries\.append # https://github.com/geopandas/geopandas/pull/3460 -geopandas\.(geoseries\.)?GeoSeries\.select # https://github.com/geopandas/geopandas/pull/3394 - # Inconsistent (TODO) geopandas\.(geoseries\.)?GeoSeries\.apply geopandas\.(geoseries\.)?GeoSeries\.fillna diff --git a/stubs/geopandas/METADATA.toml b/stubs/geopandas/METADATA.toml index a47a9a46e2e2..b70a1c4806fa 100644 --- a/stubs/geopandas/METADATA.toml +++ b/stubs/geopandas/METADATA.toml @@ -1,6 +1,6 @@ -version = "1.0.1" +version = "1.1.0" # Requires a version of numpy with a `py.typed` file -requires = ["numpy>=1.20", "pandas-stubs<2.2.3.250527", "types-shapely", "pyproj"] +requires = ["numpy>=1.20", "pandas-stubs", "types-shapely", "pyproj"] upstream_repository = "https://github.com/geopandas/geopandas" [tool.stubtest] diff --git a/stubs/geopandas/geopandas/accessors.pyi b/stubs/geopandas/geopandas/accessors.pyi new file mode 100644 index 000000000000..d69a67fe594b --- /dev/null +++ b/stubs/geopandas/geopandas/accessors.pyi @@ -0,0 +1,7 @@ +from typing import Any + +import pandas as pd + +class GeoSeriesAccessor: + def __init__(self, series: pd.Series[Any]) -> None: ... # Cannot use pd.Series[BaseGeometry] + def __getattr__(self, name: str) -> Any: ... # Delegate all attributes to the GeoSeries diff --git a/stubs/geopandas/geopandas/array.pyi b/stubs/geopandas/geopandas/array.pyi index c6ba2b330406..7572dd5b5c48 100644 --- a/stubs/geopandas/geopandas/array.pyi +++ b/stubs/geopandas/geopandas/array.pyi @@ -1,7 +1,7 @@ import builtins from _typeshed import Incomplete, Unused -from collections.abc import Callable, Sequence -from typing import Any, ClassVar, Literal, NoReturn, SupportsIndex, TypeVar, overload +from collections.abc import Callable, Collection, Sequence +from typing import Any, ClassVar, Final, Literal, NoReturn, SupportsIndex, TypeVar, overload from typing_extensions import Self, TypeAlias, deprecated import numpy as np @@ -21,11 +21,14 @@ _Array2D: TypeAlias = np.ndarray[tuple[int, int], np.dtype[_ScalarType]] _ArrayOrGeom: TypeAlias = GeometryArray | ArrayLike | Geometry TransformerFromCRS = Transformer.from_crs +POLYGON_GEOM_TYPES: Final[set[str]] +LINE_GEOM_TYPES: Final[set[str]] +POINT_GEOM_TYPES: Final[set[str]] class GeometryDtype(ExtensionDtype): type: ClassVar[type[BaseGeometry]] name: ClassVar[str] - na_value: float + na_value: None @classmethod def construct_from_string(cls, string: str) -> Self: ... @classmethod @@ -35,14 +38,14 @@ def isna(value: object) -> bool: ... def from_shapely(data, crs: _ConvertibleToCRS | None = None) -> GeometryArray: ... def to_shapely(geoms: GeometryArray) -> _Array1D[np.object_]: ... def from_wkb( - data, crs: _ConvertibleToCRS | None = None, on_invalid: Literal["raise", "warn", "ignore"] = "raise" + data, crs: _ConvertibleToCRS | None = None, on_invalid: Literal["raise", "warn", "ignore", "fix"] = "raise" ) -> GeometryArray: ... @overload def to_wkb(geoms: GeometryArray, hex: Literal[False] = False, **kwargs) -> _Array1D[np.bytes_]: ... @overload def to_wkb(geoms: GeometryArray, hex: Literal[True], **kwargs) -> _Array1D[np.str_]: ... def from_wkt( - data, crs: _ConvertibleToCRS | None = None, on_invalid: Literal["raise", "warn", "ignore"] = "raise" + data, crs: _ConvertibleToCRS | None = None, on_invalid: Literal["raise", "warn", "ignore", "fix"] = "raise" ) -> GeometryArray: ... def to_wkt(geoms: GeometryArray, **kwargs) -> _Array1D[np.str_]: ... def points_from_xy( @@ -80,6 +83,8 @@ class GeometryArray(ExtensionArray): @property def is_valid(self) -> _Array1D[np.bool_]: ... def is_valid_reason(self) -> _Array1D[np.object_]: ... + def is_valid_coverage(self, gap_width: float = 0.0) -> bool: ... + def invalid_coverage_edges(self, gap_width: float = 0.0) -> _Array1D[np.object_]: ... @property def is_empty(self) -> _Array1D[np.bool_]: ... @property @@ -93,6 +98,8 @@ class GeometryArray(ExtensionArray): @property def has_z(self) -> _Array1D[np.bool_]: ... @property + def has_m(self) -> _Array1D[np.bool_]: ... + @property def geom_type(self) -> _Array1D[np.str_]: ... @property def area(self) -> _Array1D[np.float64]: ... @@ -108,6 +115,7 @@ class GeometryArray(ExtensionArray): @property def centroid(self) -> GeometryArray: ... def concave_hull(self, ratio: float, allow_holes: bool) -> _Array1D[np.object_]: ... + def constrained_delaunay_triangles(self) -> GeometryArray: ... @property def convex_hull(self) -> GeometryArray: ... @property @@ -128,10 +136,13 @@ class GeometryArray(ExtensionArray): def remove_repeated_points(self, tolerance: float | ArrayLike = 0.0) -> GeometryArray: ... def representative_point(self) -> GeometryArray: ... def minimum_bounding_circle(self) -> GeometryArray: ... + def maximum_inscribed_circle(self, tolerance: float | ArrayLike) -> GeometryArray: ... def minimum_bounding_radius(self) -> _Array1D[np.float64]: ... def minimum_clearance(self) -> _Array1D[np.float64]: ... + def minimum_clearance_line(self) -> GeometryArray: ... def normalize(self) -> GeometryArray: ... - def make_valid(self) -> GeometryArray: ... + def orient_polygons(self, exterior_cw: bool = False) -> GeometryArray: ... + def make_valid(self, method: Literal["linework", "structure"] = "linework", keep_collapsed: bool = True) -> GeometryArray: ... def reverse(self) -> GeometryArray: ... def segmentize(self, max_segment_length: float | ArrayLike) -> GeometryArray: ... def force_2d(self) -> GeometryArray: ... @@ -156,8 +167,7 @@ class GeometryArray(ExtensionArray): def within(self, other: _ArrayOrGeom) -> _Array1D[np.bool_]: ... def dwithin(self, other: _ArrayOrGeom, distance: float) -> _Array1D[np.bool_]: ... def geom_equals_exact(self, other: _ArrayOrGeom, tolerance: float | ArrayLike) -> _Array1D[np.bool_]: ... - @deprecated("Use method `geom_equals_exact` instead.") - def geom_almost_equals(self, other: _ArrayOrGeom, decimal: float) -> _Array1D[np.bool_]: ... + def geom_equals_identical(self, other: _ArrayOrGeom) -> _Array1D[np.bool_]: ... def clip_by_rect(self, xmin: float, ymin: float, xmax: float, ymax: float) -> GeometryArray: ... def difference(self, other: _ArrayOrGeom) -> GeometryArray: ... def intersection(self, other: _ArrayOrGeom) -> GeometryArray: ... @@ -172,14 +182,17 @@ class GeometryArray(ExtensionArray): def buffer(self, distance: float | ArrayLike, resolution: int = 16, **kwargs) -> GeometryArray: ... def interpolate(self, distance: float | ArrayLike, normalized: bool = False) -> GeometryArray: ... def simplify(self, tolerance: float | ArrayLike, preserve_topology: bool = True) -> GeometryArray: ... + def simplify_coverage(self, tolerance: float | ArrayLike, simplify_boundary: bool = True) -> GeometryArray: ... def project(self, other: _ArrayOrGeom, normalized: bool = False) -> _Array1D[np.float64]: ... def relate(self, other: _ArrayOrGeom) -> _Array1D[np.str_]: ... def relate_pattern(self, other: _ArrayOrGeom, pattern: str) -> _Array1D[np.bool_]: ... @deprecated("Use method `union_all` instead.") def unary_union(self) -> BaseGeometry: ... - def union_all(self, method: Literal["coverage", "unary"] = "unary") -> BaseGeometry: ... + def union_all( + self, method: Literal["coverage", "unary", "disjoint_subset"] = "unary", grid_size: float | None = None + ) -> BaseGeometry: ... def intersection_all(self) -> BaseGeometry: ... - def affine_transform(self, matrix) -> GeometryArray: ... + def affine_transform(self, matrix: Collection[float]) -> GeometryArray: ... def translate(self, xoff: float = 0.0, yoff: float = 0.0, zoff: float = 0.0) -> GeometryArray: ... def rotate(self, angle: float, origin: _AffinityOrigin = "center", use_radians: bool = False) -> GeometryArray: ... def scale( @@ -197,21 +210,20 @@ class GeometryArray(ExtensionArray): @property def z(self) -> _Array1D[np.float64]: ... @property + def m(self) -> _Array1D[np.float64]: ... + @property def bounds(self) -> _Array2D[np.float64]: ... @property def total_bounds(self) -> _Array1D[np.float64]: ... @property def size(self) -> int: ... @property - def shape(self) -> tuple[int]: ... # Always 1-D, this is not a mistake + def shape(self) -> tuple[int]: ... # Always 1-D, this is not mistaken for tuple[int, ...] @property def ndim(self) -> Literal[1]: ... def copy(self, *args: Unused, **kwargs: Unused) -> GeometryArray: ... def take( - self, - indices: Sequence[SupportsIndex] | NDArray[np.integer[Any]], # np.integer[Any] because precision is not important - allow_fill: bool = False, - fill_value: Geometry | None = None, + self, indices: Sequence[SupportsIndex] | NDArray[np.integer], allow_fill: bool = False, fill_value: Geometry | None = None ) -> GeometryArray: ... def fillna( self, @@ -239,6 +251,8 @@ class GeometryArray(ExtensionArray): def __ne__(self, other: object) -> _Array1D[np.bool_]: ... # type: ignore[override] def __contains__(self, item: object) -> np.bool_: ... +# TODO: Improve `func` type with a callable protocol (with overloads for 2D and 3D geometries) def transform( - data: NDArray[np.object_], func: Callable[[NDArray[np.float64], NDArray[np.float64]], NDArray[np.float64]] + data: NDArray[np.object_] | GeometryArray | pd.Series[Any], # Cannot use pd.Series[BaseGeometry] + func: Callable[..., NDArray[np.float64]], ) -> NDArray[np.object_]: ... diff --git a/stubs/geopandas/geopandas/base.pyi b/stubs/geopandas/geopandas/base.pyi index 1c5c3dddbfe4..979c4fcbebef 100644 --- a/stubs/geopandas/geopandas/base.pyi +++ b/stubs/geopandas/geopandas/base.pyi @@ -1,5 +1,5 @@ from _typeshed import Incomplete, SupportsGetItem -from collections.abc import Callable, Hashable, Iterable, Mapping, Sequence +from collections.abc import Callable, Collection, Hashable, Iterable, Mapping, Sequence from typing import Any, Literal, Protocol, SupportsIndex, overload, type_check_only from typing_extensions import Self, TypeAlias, deprecated @@ -64,6 +64,8 @@ class GeoPandasBase: @property def is_valid(self) -> pd.Series[bool]: ... def is_valid_reason(self) -> pd.Series[str]: ... + def is_valid_coverage(self, *, gap_width: float = 0.0) -> bool: ... + def invalid_coverage_edges(self, *, gap_width: float = 0.0) -> GeoSeries: ... @property def is_empty(self) -> pd.Series[bool]: ... def count_coordinates(self) -> pd.Series[int]: ... @@ -79,6 +81,8 @@ class GeoPandasBase: def is_closed(self) -> pd.Series[bool]: ... @property def has_z(self) -> pd.Series[bool]: ... + @property + def has_m(self) -> pd.Series[bool]: ... def get_precision(self) -> pd.Series[float]: ... def get_geometry(self, index: SupportsIndex | ArrayLike) -> GeoSeries: ... @property @@ -86,6 +90,7 @@ class GeoPandasBase: @property def centroid(self) -> GeoSeries: ... def concave_hull(self, ratio: float = 0.0, allow_holes: bool = False) -> GeoSeries: ... + def constrained_delaunay_triangles(self) -> GeoSeries: ... @property def convex_hull(self) -> GeoSeries: ... def delaunay_triangles(self, tolerance: float | ArrayLike = 0.0, only_edges: bool | ArrayLike = False) -> GeoSeries: ... @@ -113,10 +118,13 @@ class GeoPandasBase: ) -> GeoSeries: ... def representative_point(self) -> GeoSeries: ... def minimum_bounding_circle(self) -> GeoSeries: ... + def maximum_inscribed_circle(self, *, tolerance: float | ArrayLike | None = None) -> GeoSeries: ... def minimum_bounding_radius(self) -> pd.Series[float]: ... def minimum_clearance(self) -> pd.Series[float]: ... + def minimum_clearance_line(self) -> GeoSeries: ... def normalize(self) -> GeoSeries: ... - def make_valid(self) -> GeoSeries: ... + def orient_polygons(self, *, exterior_cw: bool = False) -> GeoSeries: ... + def make_valid(self, *, method: Literal["linework", "structure"] = "linework", keep_collapsed: bool = True) -> GeoSeries: ... def reverse(self) -> GeoSeries: ... def segmentize(self, max_segment_length: float | ArrayLike) -> GeoSeries: ... def transform( @@ -126,18 +134,20 @@ class GeoPandasBase: def force_3d(self, z: float | ArrayLike = 0) -> GeoSeries: ... def line_merge(self, directed: bool = False) -> GeoSeries: ... @property + @deprecated("Use method `union_all` instead.") def unary_union(self) -> BaseGeometry: ... - def union_all(self, method: Literal["coverage", "unary"] = "unary") -> BaseGeometry: ... + def union_all( + self, method: Literal["coverage", "unary", "disjoint_subset"] = "unary", *, grid_size: float | None = None + ) -> BaseGeometry: ... def intersection_all(self) -> BaseGeometry: ... def contains(self, other: GeoSeries | Geometry, align: bool | None = None) -> pd.Series[bool]: ... def contains_properly(self, other: GeoSeries | Geometry, align: bool | None = None) -> pd.Series[bool]: ... def dwithin(self, other: GeoSeries | Geometry, distance: float | ArrayLike, align: bool | None = None) -> pd.Series[bool]: ... def geom_equals(self, other: GeoSeries | Geometry, align: bool | None = None) -> pd.Series[bool]: ... - @deprecated("Use method `geom_equals_exact` instead.") - def geom_almost_equals(self, other: GeoSeries | Geometry, decimal: int = 6, align: bool | None = None) -> pd.Series[bool]: ... def geom_equals_exact( self, other: GeoSeries | Geometry, tolerance: float | ArrayLike, align: bool | None = None ) -> pd.Series[bool]: ... + def geom_equals_identical(self, other: GeoSeries | Geometry, align: bool | None = None) -> pd.Series[bool]: ... def crosses(self, other: GeoSeries | Geometry, align: bool | None = None) -> pd.Series[bool]: ... def disjoint(self, other: GeoSeries | Geometry, align: bool | None = None) -> pd.Series[bool]: ... def intersects(self, other: GeoSeries | Geometry, align: bool | None = None) -> pd.Series[bool]: ... @@ -180,11 +190,12 @@ class GeoPandasBase: **kwargs, ) -> GeoSeries: ... def simplify(self, tolerance: float | ArrayLike, preserve_topology: bool = True) -> GeoSeries: ... + def simplify_coverage(self, tolerance: float | ArrayLike, *, simplify_boundary: bool = True) -> GeoSeries: ... def relate(self, other: GeoSeries | Geometry, align: bool | None = None) -> pd.Series[str]: ... def relate_pattern(self, other: GeoSeries | Geometry, pattern: str, align: bool | None = None) -> pd.Series[bool]: ... def project(self, other: GeoSeries | Geometry, normalized: bool = False, align: bool | None = None) -> pd.Series[float]: ... def interpolate(self, distance: float | ArrayLike, normalized: bool = False) -> GeoSeries: ... - def affine_transform(self, matrix) -> GeoSeries: ... + def affine_transform(self, matrix: Collection[float]) -> GeoSeries: ... def translate(self, xoff: float = 0.0, yoff: float = 0.0, zoff: float = 0.0) -> GeoSeries: ... def rotate(self, angle: float, origin: _AffinityOrigin = "center", use_radians: bool = False) -> GeoSeries: ... def scale( @@ -195,7 +206,9 @@ class GeoPandasBase: ) -> GeoSeries: ... @property def cx(self) -> SupportsGetItem[tuple[SupportsIndex | slice, SupportsIndex | slice], Self]: ... - def get_coordinates(self, include_z: bool = False, ignore_index: bool = False, index_parts: bool = False) -> pd.DataFrame: ... + def get_coordinates( + self, include_z: bool = False, ignore_index: bool = False, index_parts: bool = False, *, include_m: bool = False + ) -> pd.DataFrame: ... def hilbert_distance( self, total_bounds: tuple[float, float, float, float] | Iterable[float] | None = None, level: int = 16 ) -> pd.Series[int]: ... diff --git a/stubs/geopandas/geopandas/geodataframe.pyi b/stubs/geopandas/geopandas/geodataframe.pyi index 7f30a113b0ab..b9d6c6d5dbc0 100644 --- a/stubs/geopandas/geopandas/geodataframe.pyi +++ b/stubs/geopandas/geopandas/geodataframe.pyi @@ -1,14 +1,14 @@ import io import os from _typeshed import Incomplete, SupportsGetItem, SupportsLenAndGetItem, SupportsRead, SupportsWrite -from collections.abc import Callable, Container, Hashable, Iterable, Iterator, Mapping +from collections.abc import Callable, Container, Hashable, Iterable, Iterator, Mapping, Sequence from json import JSONEncoder from typing import Any, Literal, overload from typing_extensions import Self import pandas as pd from numpy.typing import ArrayLike -from pandas._typing import AggFuncTypeFrame, AstypeArg, Axes, Axis, Dtype, GroupByObject, IndexLabel, Scalar +from pandas._typing import AggFuncTypeFrame, Axes, Axis, Dtype, GroupByObject, IndexLabel, Scalar from pyproj import CRS from ._decorator import doc @@ -160,7 +160,9 @@ class GeoDataFrame(GeoPandasBase, pd.DataFrame): # type: ignore[misc] chunksize: None = None, ) -> GeoDataFrame: ... @classmethod - def from_arrow(cls, table, geometry: str | None = None) -> GeoDataFrame: ... # table: pyarrow.Table + def from_arrow( + cls, table, geometry: str | None = None, to_pandas_kwargs: Mapping[str, Incomplete] | None = None + ) -> GeoDataFrame: ... # TODO: `table: pyarrow.Table | table-like` def to_json( # type: ignore[override] self, na: str = "null", @@ -306,16 +308,11 @@ class GeoDataFrame(GeoPandasBase, pd.DataFrame): # type: ignore[misc] sort: bool = True, observed: bool = False, dropna: bool = True, - method: Literal["coverage", "unary"] = "unary", + method: Literal["coverage", "unary", "disjoint_subset"] = "unary", + grid_size: float | None = None, **kwargs, ) -> GeoDataFrame: ... def explode(self, column: IndexLabel | None = None, ignore_index: bool = False, index_parts: bool = False) -> Self: ... - def astype( - self, - dtype: AstypeArg | Mapping[Any, Dtype] | pd.Series[Any], # any because of mapping invariance and series typevar bounds - copy: bool | None = None, - errors: Literal["ignore", "raise"] = "raise", - ) -> GeoDataFrame: ... def to_postgis( self, name: str, @@ -334,12 +331,15 @@ class GeoDataFrame(GeoPandasBase, pd.DataFrame): # type: ignore[misc] def sjoin( self, df: GeoDataFrame, - # *args, **kwargs passed to geopandas.sjoin how: Literal["left", "right", "inner"] = "inner", predicate: str = "intersects", lsuffix: str = "left", rsuffix: str = "right", + *, + # **kwargs passed to geopandas.sjoin distance: float | ArrayLike | None = None, + on_attribute: str | Sequence[str] | None = None, + **kwargs, ) -> GeoDataFrame: ... def sjoin_nearest( self, diff --git a/stubs/geopandas/geopandas/geoseries.pyi b/stubs/geopandas/geopandas/geoseries.pyi index bb45f01cd6be..09a38d336f87 100644 --- a/stubs/geopandas/geopandas/geoseries.pyi +++ b/stubs/geopandas/geopandas/geoseries.pyi @@ -1,14 +1,14 @@ import io import json import os -from _typeshed import Incomplete, SupportsRead, Unused +from _typeshed import Incomplete, SupportsRead from collections.abc import Callable, Hashable from typing import Any, Literal, final, overload from typing_extensions import Self import pandas as pd from numpy.typing import ArrayLike -from pandas._typing import Axes, AxisIndex, Dtype +from pandas._typing import Axes, Dtype from pyproj import CRS from shapely.geometry.base import BaseGeometry @@ -55,6 +55,8 @@ class GeoSeries(GeoPandasBase, pd.Series[BaseGeometry]): # type: ignore[type-va def y(self) -> pd.Series[float]: ... @property def z(self) -> pd.Series[float]: ... + @property + def m(self) -> pd.Series[float]: ... # Keep inline with GeoDataFrame.from_file and geopandas.io.file._read_file @classmethod def from_file( @@ -76,7 +78,7 @@ class GeoSeries(GeoPandasBase, pd.Series[BaseGeometry]): # type: ignore[type-va data: ArrayLike, # array-like of bytes handled by shapely.from_wkb(data) index: Axes | None = None, crs: _ConvertibleToCRS | None = None, - on_invalid: Literal["raise", "warn", "ignore"] = "raise", + on_invalid: Literal["raise", "warn", "ignore", "fix"] = "raise", *, dtype: Dtype | None = None, name: Hashable = None, @@ -89,7 +91,7 @@ class GeoSeries(GeoPandasBase, pd.Series[BaseGeometry]): # type: ignore[type-va data: ArrayLike, # array-like of str handled by shapely.from_wkt(data) index: Axes | None = None, crs: _ConvertibleToCRS | None = None, - on_invalid: Literal["raise", "warn", "ignore"] = "raise", + on_invalid: Literal["raise", "warn", "ignore", "fix"] = "raise", *, dtype: Dtype | None = None, name: Hashable = None, @@ -145,11 +147,7 @@ class GeoSeries(GeoPandasBase, pd.Series[BaseGeometry]): # type: ignore[type-va overwrite: bool | None = ..., **kwargs, # engine and driver dependent ) -> None: ... - # *** TODO: compare `__getitem__` with pandas-stubs *** - # def __getitem__(self, key): ... - # *** `sort_index` is annotated with `-> Self` in pandas-stubs; no need to override it *** - # def sort_index(self, *args, **kwargs): ... - def take(self, indices: ArrayLike, axis: AxisIndex = 0, **kwargs: Unused) -> GeoSeries: ... + # *** `__getitem__`, `sort_index` and `take` are annotated with `-> Self` in pandas-stubs; no need to override them *** # *** `apply` annotation in pandas-stubs is compatible except for deprecated `convert_dtype` argument *** # def apply(self, func, convert_dtype: bool | None = None, args=(), **kwargs): ... def isna(self) -> pd.Series[bool]: ... diff --git a/stubs/geopandas/geopandas/io/_geoarrow.pyi b/stubs/geopandas/geopandas/io/_geoarrow.pyi index a0f185fe48dc..d4a53581cb8b 100644 --- a/stubs/geopandas/geopandas/io/_geoarrow.pyi +++ b/stubs/geopandas/geopandas/io/_geoarrow.pyi @@ -1,6 +1,15 @@ from _typeshed import Incomplete -from typing import Literal -from typing_extensions import TypeAlias +from collections.abc import Mapping +from typing import ( + # pyarrow types returned as Any to avoid depending on pyarrow (40 MB) in stubs + Any as _PAArray, + Any as _PAField, + Any as _PATable, + Literal, + Protocol, + type_check_only, +) +from typing_extensions import CapsuleType, TypeAlias import numpy as np from numpy.typing import NDArray @@ -8,22 +17,30 @@ from numpy.typing import NDArray from ..array import GeometryArray from ..geodataframe import GeoDataFrame -_PATable: TypeAlias = Incomplete -_PAField: TypeAlias = Incomplete -_PAArray: TypeAlias = Incomplete - # Literal for language server completions and str because runtime normalizes to lowercase _GeomEncoding: TypeAlias = Literal["WKB", "geoarrow"] | str # noqa: Y051 +@type_check_only +class _PyarrowTableLike(Protocol): + def __arrow_c_stream__(self, requested_schema=None) -> CapsuleType: ... + +@type_check_only +class _PyarrowFieldLike(Protocol): + def __arrow_c_schema__(self) -> CapsuleType: ... + +@type_check_only +class _PyarrowArrayLike(Protocol): + def __arrow_c_array__(self) -> tuple[CapsuleType, CapsuleType]: ... + GEOARROW_ENCODINGS: list[str] class ArrowTable: - def __init__(self, pa_table: _PATable) -> None: ... - def __arrow_c_stream__(self, requested_schema=None): ... + def __init__(self, pa_table: _PyarrowTableLike) -> None: ... + def __arrow_c_stream__(self, requested_schema=None) -> CapsuleType: ... class GeoArrowArray: - def __init__(self, pa_field: _PAField, pa_array: _PAArray) -> None: ... - def __arrow_c_array__(self, requested_schema=None) -> tuple[Incomplete, Incomplete]: ... + def __init__(self, pa_field: _PyarrowFieldLike, pa_array: _PyarrowArrayLike) -> None: ... + def __arrow_c_array__(self, requested_schema=None) -> tuple[CapsuleType, CapsuleType]: ... def geopandas_to_arrow( df: GeoDataFrame, @@ -43,6 +60,8 @@ def construct_geometry_array( crs: str | None = None, interleaved: bool = True, ) -> tuple[_PAField, _PAArray]: ... -def arrow_to_geopandas(table, geometry: str | None = None) -> GeoDataFrame: ... +def arrow_to_geopandas( + table, geometry: str | None = None, to_pandas_kwargs: Mapping[str, Incomplete] | None = None +) -> GeoDataFrame: ... def arrow_to_geometry_array(arr) -> GeometryArray: ... def construct_shapely_array(arr: _PAArray, extension_name: str) -> NDArray[np.object_]: ... diff --git a/stubs/geopandas/geopandas/io/arrow.pyi b/stubs/geopandas/geopandas/io/arrow.pyi index a82a238aef9f..88e2419b8d1e 100644 --- a/stubs/geopandas/geopandas/io/arrow.pyi +++ b/stubs/geopandas/geopandas/io/arrow.pyi @@ -1,22 +1,28 @@ import os -from _typeshed import SupportsGetItem, SupportsKeysAndGetItem -from collections.abc import Iterable +from _typeshed import Incomplete, SupportsGetItem, SupportsKeysAndGetItem +from collections.abc import Iterable, Mapping from typing import Any, Final from ..geodataframe import GeoDataFrame METADATA_VERSION: Final[str] +SUPPORTED_VERSIONS_LITERAL = Incomplete SUPPORTED_VERSIONS: Final[list[str]] GEOARROW_ENCODINGS: Final[list[str]] SUPPORTED_ENCODINGS: Final[list[str]] +PARQUET_GEOMETRY_ENCODINGS = Incomplete def _read_parquet( path: str | os.PathLike[str], columns: Iterable[str] | None = None, storage_options: SupportsKeysAndGetItem[str, Any] | None = None, # type depend on the connection bbox: SupportsGetItem[int, float] | None = None, + to_pandas_kwargs: Mapping[str, Incomplete] | None = None, **kwargs, # kwargs passed to pyarrow.parquet.read_table ) -> GeoDataFrame: ... def _read_feather( - path: str | os.PathLike[str], columns: Iterable[str] | None = None, **kwargs # kwargs passed to pyarrow.feather.read_table + path: str | os.PathLike[str], + columns: Iterable[str] | None = None, + to_pandas_kwargs: Mapping[str, Incomplete] | None = None, + **kwargs, # kwargs passed to pyarrow.feather.read_table ) -> GeoDataFrame: ... diff --git a/stubs/geopandas/geopandas/plotting.pyi b/stubs/geopandas/geopandas/plotting.pyi index eadbb6445d1b..01528e6284e4 100644 --- a/stubs/geopandas/geopandas/plotting.pyi +++ b/stubs/geopandas/geopandas/plotting.pyi @@ -198,7 +198,7 @@ class GeoplotAccessor(PlotAccessor): @overload def __call__( self, - column: Hashable | None = None, + column: Hashable | pd.Series | pd.Index | NDArray | None = None, cmap: str | Colormap | None = None, color: _ColorOrColors | None = None, ax: Axes | None = None, @@ -229,7 +229,7 @@ class GeoplotAccessor(PlotAccessor): ) -> Axes: ... def geo( self, - column: Hashable | None = None, + column: Hashable | pd.Series | pd.Index | NDArray | None = None, cmap: str | Colormap | None = None, color: _ColorOrColors | None = None, ax: Axes | None = None, diff --git a/stubs/geopandas/geopandas/sindex.pyi b/stubs/geopandas/geopandas/sindex.pyi index bd2611478d72..211c04069a9c 100644 --- a/stubs/geopandas/geopandas/sindex.pyi +++ b/stubs/geopandas/geopandas/sindex.pyi @@ -21,7 +21,7 @@ class SpatialIndex: predicate: str | None = None, sort: bool = False, distance: float | ArrayLike | None = None, - output_format: Literal["tuple"] = "tuple", + output_format: Literal["indices"] = "indices", ) -> NDArray[np.int64]: ... @overload def query(