Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,15 @@ jobs:
- name: Install dependencies
run: uv sync --frozen
- run: uv run python run.py ty-check
pyrefly:
name: Run pyrefly on the tests and on the stubs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
save-cache: "false"
- name: Install dependencies
run: uv sync --frozen
- run: uv run python run.py pyrefly-check
20 changes: 16 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ dev = [
"mypy[native-parser]>=2.1.0",
"pyright>=1.1.409",
"ty>=0.0.40",
"pyrefly>=1.0.0",
{ include-group = "tests" },
]

Expand Down Expand Up @@ -94,9 +95,6 @@ native_parser = true
# Project settings
stubPath = "stubs/"
enableTypeIgnoreComments = false # Leave "type: ignore" comments to mypy
ignore = [
"**/site-packages/", # Disable annoying checks in third-party library code
]

# Strict mode
typeCheckingMode = "strict"
Expand Down Expand Up @@ -124,8 +122,22 @@ reportSelfClsParameterName = "none"

[tool.ty]
analysis.respect-type-ignore-comments = false
rules.invalid-method-override = "ignore" # out of control of the stubs (inherited from implementation)
terminal.output-format = "concise"

[tool.ty.rules]
deprecated = "error"
invalid-method-override = "ignore" # out of control of the stubs (inherited from implementation)

[tool.pyrefly]
search-path = ["stubs/"]
enabled-ignores = ["pyrefly"]
output-format = "min-text"

[tool.pyrefly.errors]
deprecated = "error"
# Out of control of the stubs (inherited from implementation)
bad-override = false
inconsistent-inheritance = false

[tool.pytest.ini_options]
testpaths = ["tests"]
1 change: 1 addition & 0 deletions run.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"mypy": ["tests", "stubs"],
"pyright": ["tests", "stubs"],
"ty-check": ["tests", "stubs"],
"pyrefly-check": ["tests", "stubs"],
"stubtest": ["--allowlist=stubtest_allowlist.txt", "pandapower", "pyogrio"],
"pytest": [],
}
Expand Down
2 changes: 1 addition & 1 deletion stubs/pandapower-stubs/auxiliary.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ class GeoAccessor:
@property
def type(self) -> str: ...
@property
def as_shapely_obj(self) -> pd.Series[BaseGeometry]: ... # type: ignore[type-var] # pyright: ignore[reportInvalidTypeArguments] # ty:ignore[invalid-type-arguments]
def as_shapely_obj(self) -> pd.Series[BaseGeometry]: ... # type: ignore[type-var] # pyright: ignore[reportInvalidTypeArguments] # ty:ignore[invalid-type-arguments] # pyrefly:ignore[bad-specialization]
@property
def as_geoseries(self) -> gpd.GeoSeries: ...
def __getattr__(self, item: str) -> Any: ...
Expand Down
2 changes: 1 addition & 1 deletion stubs/pandapower-stubs/plotting/plotly/draw_layers.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ from collections.abc import Sequence
from pathlib import Path
from typing import Any, Literal

import plotly.graph_objs as go # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import]
import plotly.graph_objs as go # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] # pyrefly:ignore[missing-import]

def version_check() -> None: ...
def draw_layers(
Expand Down
2 changes: 1 addition & 1 deletion stubs/pandapower-stubs/plotting/plotly/layers_plotly.pyi
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from _typeshed import SupportsGetItem
from typing import Literal

import plotly.graph_objs as go # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import]
import plotly.graph_objs as go # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] # pyrefly:ignore[missing-import]

from pandapower.auxiliary import pandapowerNet

Expand Down
2 changes: 1 addition & 1 deletion stubs/pandapower-stubs/plotting/plotly/pf_res_plotly.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Literal

import plotly.graph_objs as go # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import]
import plotly.graph_objs as go # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] # pyrefly:ignore[missing-import]

from pandapower.auxiliary import pandapowerNet
from pandapower.plotting.plotly.mapbox_plot import *
Expand Down
2 changes: 1 addition & 1 deletion stubs/pandapower-stubs/plotting/plotly/simple_plotly.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ from collections.abc import Iterable, Mapping
from typing import Any, Literal, overload

import pandas as pd
import plotly.graph_objs as go # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import]
import plotly.graph_objs as go # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] # pyrefly:ignore[missing-import]

from pandapower.auxiliary import pandapowerNet
from pandapower.plotting.plotly.mapbox_plot import *
Expand Down
2 changes: 1 addition & 1 deletion stubs/pandapower-stubs/plotting/plotly/traces.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ from collections.abc import Collection, Iterable, Mapping
from typing import Any, Literal

import pandas as pd
import plotly.graph_objs as go # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import]
import plotly.graph_objs as go # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] # pyrefly:ignore[missing-import]

from pandapower._typing import Float, Int
from pandapower.auxiliary import pandapowerNet
Expand Down
2 changes: 1 addition & 1 deletion stubs/pandapower-stubs/plotting/plotly/vlevel_plotly.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Literal

import plotly.graph_objs as go # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import]
import plotly.graph_objs as go # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] # pyrefly:ignore[missing-import]

from pandapower.auxiliary import pandapowerNet
from pandapower.plotting.plotly.traces import _MapStyle
Expand Down
2 changes: 1 addition & 1 deletion stubs/pandapower-stubs/topology/graph_tool_interface.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ from _typeshed import Incomplete
from collections.abc import Iterable
from typing import Literal

from graph_tool import ( # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import]
from graph_tool import ( # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] # pyrefly:ignore[missing-import]
Graph,
)

Expand Down
2 changes: 1 addition & 1 deletion stubs/psqlextra-stubs/error.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django import db
from psycopg import ( # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import]
from psycopg import ( # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] # ty:ignore[unresolved-import] # pyrefly:ignore[missing-import]
Error as _Psycopg3Error,
)
from psycopg2 import Error as _Psycopg2Error
Expand Down
8 changes: 4 additions & 4 deletions tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import numpy as np
from shapely.geometry.base import BaseMultipartGeometry, GeometrySequence

type _ClassInfo = type | UnionType | tuple["_ClassInfo", ...] # see isinstance
type _ClassInfo = type | UnionType | tuple[_ClassInfo, ...] # see isinstance

# Make stubs generic classes generic at runtime
setattr(BaseMultipartGeometry, "__class_getitem__", classmethod(GenericAlias))
Expand All @@ -16,20 +16,20 @@

def check[T](obj: T, cls: _ClassInfo, dtype: _ClassInfo | None = None) -> T:
__tracebackhide__ = True
if not isinstance(obj, cls):
if not isinstance(obj, cls): # pyrefly:ignore[invalid-argument]
raise RuntimeError(f"Expected type '{cls}' but got '{type(obj)}'")
if dtype is None:
return obj

value: Any
if isinstance(obj, np.ndarray):
value = np.asarray(obj).flatten()[0] # pyright: ignore[reportUnknownArgumentType]
value = np.asarray(obj).flatten()[0] # pyright:ignore[reportUnknownArgumentType]
elif hasattr(obj, "__iter__"):
value = next(iter(cast(Iterable[Any], obj)))
else:
value = obj

if not isinstance(value, dtype):
if not isinstance(value, dtype): # pyrefly:ignore[invalid-argument]
raise RuntimeError(f"Expected type '{dtype}' but got '{type(value)}'")
return obj

Expand Down
8 changes: 4 additions & 4 deletions tests/geopandas/test_explore.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ def test_explore() -> None:
if TYPE_CHECKING:
assert_type(GDF.explore(tooltip=False, popup=True, k=4, map_kwds={}), folium.Map)
assert_type(_explore(GDF, tooltip=False, popup=True, k=4, map_kwds={}), folium.Map)
GDF.explore(map_kwds=False) # type: ignore[arg-type] # pyright: ignore[reportArgumentType] # ty:ignore[invalid-argument-type]
_explore(GDF, map_kwds=False) # type: ignore[arg-type] # pyright: ignore[reportArgumentType] # ty:ignore[invalid-argument-type]
GDF.explore(map_kwds=False) # type: ignore[arg-type] # pyright:ignore[reportArgumentType] # ty:ignore[invalid-argument-type] # pyrefly:ignore[bad-argument-type]
_explore(GDF, map_kwds=False) # type: ignore[arg-type] # pyright:ignore[reportArgumentType] # ty:ignore[invalid-argument-type] # pyrefly:ignore[bad-argument-type]


def test_geoseries_explore() -> None:
Expand All @@ -27,5 +27,5 @@ def test_geoseries_explore() -> None:
_explore_geoseries(GDF.geometry, highlight=False, control_scale=False, map_kwds={}),
folium.Map,
)
GDF.geometry.explore(map_kwds=False) # type: ignore[arg-type] # pyright: ignore[reportArgumentType] # ty:ignore[invalid-argument-type]
_explore_geoseries(GDF.geometry, map_kwds=False) # type: ignore[arg-type] # pyright: ignore[reportArgumentType] # ty:ignore[invalid-argument-type]
GDF.geometry.explore(map_kwds=False) # type: ignore[arg-type] # pyright:ignore[reportArgumentType] # ty:ignore[invalid-argument-type] # pyrefly:ignore[bad-argument-type]
_explore_geoseries(GDF.geometry, map_kwds=False) # type: ignore[arg-type] # pyright:ignore[reportArgumentType] # ty:ignore[invalid-argument-type] # pyrefly:ignore[bad-argument-type]
32 changes: 16 additions & 16 deletions tests/geopandas/test_geodataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ def test_geometry() -> None:
gdf.geometry = geo.values
gdf.geometry = [Point(1, 2), Point(3, 4)]
with pytest.raises(Exception):
gdf.geometry = "geometry" # type: ignore[assignment] # pyright: ignore[reportAttributeAccessIssue] # ty:ignore[invalid-assignment]
gdf.geometry = "geometry" # type: ignore[assignment] # pyright:ignore[reportAttributeAccessIssue] # ty:ignore[invalid-assignment] # pyrefly:ignore[bad-argument-type]
with pytest.raises(Exception):
gdf.geometry = [1, 2] # type: ignore[list-item] # pyright: ignore[reportAttributeAccessIssue] # ty:ignore[invalid-assignment]
gdf.geometry = [1, 2] # type: ignore[list-item] # pyright:ignore[reportAttributeAccessIssue] # ty:ignore[invalid-assignment] # pyrefly:ignore[bad-argument-type]

# set_geometry
check(assert_type(gdf.set_geometry(geo), GeoDataFrame), GeoDataFrame)
Expand All @@ -41,7 +41,7 @@ def test_geometry() -> None:
check(assert_type(gdf.set_geometry([Point(1, 2), Point(3, 4)]), GeoDataFrame), GeoDataFrame)
check(assert_type(gdf.set_geometry("geometry"), GeoDataFrame), GeoDataFrame)
with pytest.raises(Exception):
gdf.set_geometry([1, 2]) # type: ignore[arg-type] # pyright: ignore[reportArgumentType]
gdf.set_geometry([1, 2]) # type: ignore[arg-type] # pyright:ignore[reportArgumentType] # pyrefly:ignore[bad-argument-type]

# rename_geometry
check(assert_type(gdf.rename_geometry("geom"), GeoDataFrame), GeoDataFrame)
Expand All @@ -66,7 +66,7 @@ def test_crs() -> None:
gdf.crs = "EPSG:4326"
gdf.crs = 4326
with pytest.raises(Exception):
gdf.crs = 1.5 # type: ignore[assignment] # pyright: ignore[reportAttributeAccessIssue] # ty:ignore[invalid-assignment]
gdf.crs = 1.5 # type: ignore[assignment] # pyright:ignore[reportAttributeAccessIssue] # ty:ignore[invalid-assignment] # pyrefly:ignore[bad-argument-type]

# set_crs
check(assert_type(gdf.set_crs(crs), GeoDataFrame), GeoDataFrame)
Expand All @@ -76,11 +76,11 @@ def test_crs() -> None:
check(assert_type(gdf.set_crs(crs=4326), GeoDataFrame), GeoDataFrame)
check(assert_type(gdf.set_crs(epsg=4326), GeoDataFrame), GeoDataFrame)
with pytest.raises(Exception):
gdf.set_crs() # type: ignore[call-overload] # pyright: ignore[reportCallIssue] # ty:ignore[no-matching-overload]
gdf.set_crs() # type: ignore[call-overload] # pyright:ignore[reportCallIssue] # ty:ignore[no-matching-overload] # pyrefly:ignore[no-matching-overload]
with pytest.raises(Exception):
gdf.set_crs(None) # type: ignore[call-overload] # pyright: ignore[reportArgumentType] # ty:ignore[invalid-argument-type]
gdf.set_crs(None) # type: ignore[call-overload] # pyright:ignore[reportArgumentType] # ty:ignore[invalid-argument-type] # pyrefly:ignore[bad-argument-type]
with pytest.raises(Exception):
gdf.set_crs(None, None) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] # ty:ignore[no-matching-overload]
gdf.set_crs(None, None) # type: ignore[call-overload] # pyright:ignore[reportArgumentType,reportCallIssue] # ty:ignore[no-matching-overload] # pyrefly:ignore[no-matching-overload]

# to_crs
check(assert_type(gdf.to_crs(crs), GeoDataFrame), GeoDataFrame)
Expand All @@ -90,24 +90,24 @@ def test_crs() -> None:
check(assert_type(gdf.to_crs(crs=4326), GeoDataFrame), GeoDataFrame)
check(assert_type(gdf.to_crs(epsg=4326), GeoDataFrame), GeoDataFrame)
with pytest.raises(Exception):
gdf.to_crs() # type: ignore[call-overload] # pyright: ignore[reportCallIssue] # ty:ignore[no-matching-overload]
gdf.to_crs() # type: ignore[call-overload] # pyright:ignore[reportCallIssue] # ty:ignore[no-matching-overload] # pyrefly:ignore[no-matching-overload]
with pytest.raises(Exception):
gdf.to_crs(None) # type: ignore[call-overload] # pyright: ignore[reportArgumentType] # ty:ignore[invalid-argument-type]
gdf.to_crs(None) # type: ignore[call-overload] # pyright:ignore[reportArgumentType] # ty:ignore[invalid-argument-type] # pyrefly:ignore[bad-argument-type]
with pytest.raises(Exception):
gdf.to_crs(None, None) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] # ty:ignore[no-matching-overload]
gdf.to_crs(None, None) # type: ignore[call-overload] # pyright:ignore[reportArgumentType,reportCallIssue] # ty:ignore[no-matching-overload] # pyrefly:ignore[no-matching-overload]
with pytest.raises(Exception):
gdf.to_crs(inplace=True) # type: ignore[call-overload] # pyright: ignore[reportCallIssue] # ty:ignore[no-matching-overload]
gdf.to_crs(inplace=True) # type: ignore[call-overload] # pyright:ignore[reportCallIssue] # ty:ignore[no-matching-overload] # pyrefly:ignore[no-matching-overload]
with pytest.raises(Exception):
gdf.to_crs(None, inplace=True) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] # ty:ignore[no-matching-overload]
gdf.to_crs(None, inplace=True) # type: ignore[call-overload] # pyright:ignore[reportArgumentType,reportCallIssue] # ty:ignore[no-matching-overload] # pyrefly:ignore[no-matching-overload]
with pytest.raises(Exception):
gdf.to_crs(None, None, inplace=True) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] # ty:ignore[no-matching-overload]
gdf.to_crs(None, None, inplace=True) # type: ignore[call-overload] # pyright:ignore[reportArgumentType,reportCallIssue] # ty:ignore[no-matching-overload] # pyrefly:ignore[no-matching-overload]
with pytest.raises(Exception):
gdf.to_crs(None, None, True) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] # ty:ignore[no-matching-overload]
gdf.to_crs(None, None, True) # type: ignore[call-overload] # pyright:ignore[reportArgumentType,reportCallIssue] # ty:ignore[no-matching-overload] # pyrefly:ignore[no-matching-overload]

# estimate_utm_crs
check(assert_type(gdf.estimate_utm_crs(), CRS), CRS)
check(assert_type(gdf.estimate_utm_crs("WGS 84"), CRS), CRS)
with pytest.raises(Exception):
gdf.estimate_utm_crs(84) # type: ignore[arg-type] # pyright: ignore[reportArgumentType] # ty:ignore[invalid-argument-type]
gdf.estimate_utm_crs(84) # type: ignore[arg-type] # pyright:ignore[reportArgumentType] # ty:ignore[invalid-argument-type] # pyrefly:ignore[bad-argument-type]
with pytest.raises(Exception):
gdf.estimate_utm_crs(CRS) # type: ignore[arg-type] # pyright: ignore[reportArgumentType] # ty:ignore[invalid-argument-type]
gdf.estimate_utm_crs(CRS) # type: ignore[arg-type] # pyright:ignore[reportArgumentType] # ty:ignore[invalid-argument-type] # pyrefly:ignore[bad-argument-type]
18 changes: 9 additions & 9 deletions tests/geopandas/test_geoseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def test_crs() -> None:
gs.crs = 4326
assert isinstance(gs.crs, CRS)
with pytest.raises(Exception):
gs.crs = 1.5 # type: ignore[assignment] # pyright: ignore[reportAttributeAccessIssue] # ty:ignore[invalid-assignment]
gs.crs = 1.5 # type: ignore[assignment] # pyright:ignore[reportAttributeAccessIssue] # ty:ignore[invalid-assignment] # pyrefly:ignore[bad-argument-type]

# set_crs
check(assert_type(gs.set_crs(crs), GeoSeries), GeoSeries)
Expand All @@ -53,28 +53,28 @@ def test_crs() -> None:
check(assert_type(gs.set_crs(crs=4326), GeoSeries), GeoSeries)
check(assert_type(gs.set_crs(epsg=4326), GeoSeries), GeoSeries)
with pytest.raises(Exception):
gs.set_crs() # type: ignore[call-overload] # pyright: ignore[reportCallIssue] # ty:ignore[no-matching-overload]
gs.set_crs() # type: ignore[call-overload] # pyright:ignore[reportCallIssue] # ty:ignore[no-matching-overload] # pyrefly:ignore[no-matching-overload]
with pytest.raises(Exception):
gs.set_crs(None) # type: ignore[call-overload] # pyright: ignore[reportArgumentType] # ty:ignore[invalid-argument-type]
gs.set_crs(None) # type: ignore[call-overload] # pyright:ignore[reportArgumentType] # ty:ignore[invalid-argument-type] # pyrefly:ignore[bad-argument-type]
with pytest.raises(Exception):
gs.set_crs(None, None) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] # ty:ignore[no-matching-overload]
gs.set_crs(None, None) # type: ignore[call-overload] # pyright:ignore[reportArgumentType,reportCallIssue] # ty:ignore[no-matching-overload] # pyrefly:ignore[no-matching-overload]

# to_crs
check(assert_type(gs.to_crs(crs), GeoSeries), GeoSeries)
check(assert_type(gs.to_crs("EPSG:4326"), GeoSeries), GeoSeries)
check(assert_type(gs.to_crs(crs=4326), GeoSeries), GeoSeries)
check(assert_type(gs.to_crs(epsg=4326), GeoSeries), GeoSeries)
with pytest.raises(Exception):
gs.to_crs() # type: ignore[call-overload] # pyright: ignore[reportCallIssue] # ty:ignore[no-matching-overload]
gs.to_crs() # type: ignore[call-overload] # pyright:ignore[reportCallIssue] # ty:ignore[no-matching-overload] # pyrefly:ignore[no-matching-overload]
with pytest.raises(Exception):
gs.to_crs(None) # type: ignore[call-overload] # pyright: ignore[reportArgumentType] # ty:ignore[invalid-argument-type]
gs.to_crs(None) # type: ignore[call-overload] # pyright:ignore[reportArgumentType] # ty:ignore[invalid-argument-type] # pyrefly:ignore[bad-argument-type]
with pytest.raises(Exception):
gs.to_crs(None, None) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] # ty:ignore[no-matching-overload]
gs.to_crs(None, None) # type: ignore[call-overload] # pyright:ignore[reportArgumentType,reportCallIssue] # ty:ignore[no-matching-overload] # pyrefly:ignore[no-matching-overload]

# estimate_utm_crs
check(assert_type(gs.estimate_utm_crs(), CRS), CRS)
check(assert_type(gs.estimate_utm_crs("WGS 84"), CRS), CRS)
with pytest.raises(Exception):
gs.estimate_utm_crs(84) # type: ignore[arg-type] # pyright: ignore[reportArgumentType] # ty:ignore[invalid-argument-type]
gs.estimate_utm_crs(84) # type: ignore[arg-type] # pyright:ignore[reportArgumentType] # ty:ignore[invalid-argument-type] # pyrefly:ignore[bad-argument-type]
with pytest.raises(Exception):
gs.estimate_utm_crs(CRS) # type: ignore[arg-type] # pyright: ignore[reportArgumentType] # ty:ignore[invalid-argument-type]
gs.estimate_utm_crs(CRS) # type: ignore[arg-type] # pyright:ignore[reportArgumentType] # ty:ignore[invalid-argument-type] # pyrefly:ignore[bad-argument-type]
Loading