diff --git a/backend/app/services/generative/exporters/dxf.py b/backend/app/services/generative/exporters/dxf.py index fd1eb296..d207a3c7 100644 --- a/backend/app/services/generative/exporters/dxf.py +++ b/backend/app/services/generative/exporters/dxf.py @@ -24,6 +24,11 @@ import logging # импорт из модуля удовлетворяет strict no-implicit-reexport. from ezdxf.enums import TextEntityAlignment from ezdxf.filemanagement import new as ezdxf_new + +# Modelspace определён в ezdxf.layouts.layout и не в __all__ пакета ezdxf.layouts; +# импорт из модуля-определителя удовлетворяет strict no-implicit-reexport (как ezdxf_new). +from ezdxf.layouts.layout import Modelspace +from shapely.coords import CoordinateSequence from shapely.geometry import Polygon from app.schemas.concept import ConceptVariant @@ -44,7 +49,7 @@ _LAYER_BUILDINGS = "BUILDINGS" _LABEL_HEIGHT_M = 2.0 -def _ring_points(coords: object) -> list[tuple[float, float]]: +def _ring_points(coords: CoordinateSequence) -> list[tuple[float, float]]: """Кольцо (exterior/interior) как список (x, y) для LWPolyline (без замыкающей точки).""" pts = list(coords) # Shapely дублирует первую точку в конце; close=True у ezdxf замкнёт сам. @@ -53,7 +58,7 @@ def _ring_points(coords: object) -> list[tuple[float, float]]: return [(float(x), float(y)) for x, y in pts] -def _add_polygon(msp: object, poly: Polygon, layer: str) -> None: +def _add_polygon(msp: Modelspace, poly: Polygon, layer: str) -> None: """Нарисовать полигон на слое: внешнее кольцо + каждое внутреннее (отверстие). LWPolyline не умеет дырки, поэтому каждое interior-кольцо эмитируется отдельной @@ -151,15 +156,15 @@ def _feature_to_metric_polygon(parcel: Parcel, feature: object) -> Polygon | Non return None coords = geometry.get("coordinates") # Shapely mapping() emits nested tuples; accept both tuple and list. - if not isinstance(coords, (list, tuple)) or not coords: + if not isinstance(coords, list | tuple) or not coords: return None ring = coords[0] - if not isinstance(ring, (list, tuple)) or len(ring) < 4: + if not isinstance(ring, list | tuple) or len(ring) < 4: return None metric_pts: list[tuple[float, float]] = [] for pt in ring: - if not isinstance(pt, (list, tuple)) or len(pt) < 2: + if not isinstance(pt, list | tuple) or len(pt) < 2: return None lon, lat = float(pt[0]), float(pt[1]) x, y = parcel.wgs84_to_metric(lon, lat)