Skip to content
Merged
Changes from 2 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
14 changes: 9 additions & 5 deletions geoalchemy2/shape.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,22 @@
"""

from contextlib import contextmanager
from typing import TYPE_CHECKING

try:
import shapely
import shapely.wkb
import shapely.wkt
from shapely import Geometry as ShapelyGeometry
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from shapely import Geometry as ShapelyGeometry is likely incompatible with the Shapely versions this repo supports (tox installs Shapely>=1.3.0, and optional deps declare Shapely>=1.7). In Shapely 1.x there is no top-level Geometry, so this will raise ImportError even when Shapely is installed, incorrectly setting HAS_SHAPELY=False and breaking to_shape/from_shape. Import the geometry base type from shapely.geometry.base (e.g., BaseGeometry) or otherwise use a version-compatible symbol for the annotation without causing the Shapely import block to fail.

Suggested change
from shapely import Geometry as ShapelyGeometry
from shapely.geometry.base import BaseGeometry as ShapelyGeometry

Copilot uses AI. Check for mistakes.
from shapely.wkb import dumps

HAS_SHAPELY = True
_shapely_exc = None
except ImportError as exc:
if not TYPE_CHECKING:

class ShapelyGeometry:
"""Requires shapely. Install with: pip install geoalchemy2[shapely]."""
Comment on lines +21 to +24
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The if not TYPE_CHECKING: guard prevents the stub class from being defined during static type checking. When type checkers analyze code without shapely installed (or without access to shapely's type stubs), they will encounter a NameError for ShapelyGeometry in the function signatures.

Consider removing the if not TYPE_CHECKING: condition and defining the stub class unconditionally in the except block. This ensures the stub is available in both runtime and static analysis contexts.

Suggested change
if not TYPE_CHECKING:
class ShapelyGeometry:
"""Requires shapely. Install with: pip install geoalchemy2[shapely]."""
class ShapelyGeometry:
"""Requires shapely. Install with: pip install geoalchemy2[shapely]."""

Copilot uses AI. Check for mistakes.

HAS_SHAPELY = False
_shapely_exc = exc

Expand All @@ -35,7 +41,7 @@ def check_shapely():


@check_shapely()
def to_shape(element: WKBElement | WKTElement) -> shapely.Geometry:
def to_shape(element: WKBElement | WKTElement) -> ShapelyGeometry:
"""Function to convert a :class:`geoalchemy2.types.SpatialElement` to a Shapely geometry.
Comment on lines 41 to 45
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change fixes the runtime NameError when Shapely isn't installed, but there’s no test ensuring import geoalchemy2 (or import geoalchemy2.shape) works in an environment without Shapely. Consider adding a regression test that imports/reloads geoalchemy2.shape with Shapely unavailable (e.g., via an import hook or sys.modules patch) so this doesn’t regress again.

Copilot uses AI. Check for mistakes.

Args:
Expand All @@ -61,9 +67,7 @@ def to_shape(element: WKBElement | WKTElement) -> shapely.Geometry:


@check_shapely()
def from_shape(
shape: shapely.Geometry, srid: int = -1, extended: bool | None = False
) -> WKBElement:
def from_shape(shape: ShapelyGeometry, srid: int = -1, extended: bool | None = False) -> WKBElement:
"""Function to convert a Shapely geometry to a :class:`geoalchemy2.types.WKBElement`.

Args:
Expand Down