Skip to content

Commit 2c66018

Browse files
committed
Refine and relax typed dicts as needs arise
1 parent 8051e48 commit 2c66018

1 file changed

Lines changed: 27 additions & 15 deletions

File tree

src/shapefile.py

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ class GeoJSONPoint(TypedDict):
152152
# elements. "
153153
# RFC7946 also requires long/lat easting/northing which we do not enforce,
154154
# and despite the SHOULD NOT, we may use a 4th element for Shapefile M Measures.
155-
coordinates: Point
155+
coordinates: Union[Point, tuple[()]]
156156

157157
class GeoJSONMultiPoint(TypedDict):
158158
type: Literal["MultiPoint"]
@@ -197,9 +197,11 @@ class GeoJSONFeature(TypedDict):
197197
geometry: Optional[GeoJSONObject]
198198

199199

200-
class GeoJSONFeatureCollection(TypedDict, total= False):
200+
class GeoJSONFeatureCollection(TypedDict):
201201
type: Literal["FeatureCollection"]
202202
features: list[GeoJSONFeature]
203+
204+
class GeoJSONFeatureCollectionWithBBox(GeoJSONFeatureCollection, total=False):
203205
# bbox is optional
204206
# typing.NotRequired requires Python 3.11
205207
# and we must support 3.9 (at least until October)
@@ -990,14 +992,16 @@ def __init__(self, shape: Optional[Shape] = None, record: Optional[_Record] = No
990992
def __geo_interface__(self) -> GeoJSONFeature:
991993
return {
992994
"type": "Feature",
993-
"properties": self.record.as_dict(date_strings=True),
995+
"properties": None
996+
if self.record is None
997+
else self.record.as_dict(date_strings=True),
994998
"geometry": None
995-
if self.shape.shapeType == NULL
999+
if self.shape is None or self.shape.shapeType == NULL
9961000
else self.shape.__geo_interface__,
9971001
}
9981002

9991003

1000-
class Shapes(list):
1004+
class Shapes(list[Optional[Shape]]):
10011005
"""A class to hold a list of Shape objects. Subclasses list to ensure compatibility with
10021006
former work and to reuse all the optimizations of the builtin list.
10031007
In addition to the list interface, this also provides the GeoJSON __geo_interface__
@@ -1010,14 +1014,17 @@ def __repr__(self):
10101014
def __geo_interface__(self) -> GeoJSONGeometryCollection:
10111015
# Note: currently this will fail if any of the shapes are null-geometries
10121016
# could be fixed by storing the shapefile shapeType upon init, returning geojson type with empty coords
1013-
collection = {
1014-
"type": "GeometryCollection",
1015-
"geometries": [shape.__geo_interface__ for shape in self],
1016-
}
1017+
collection = GeoJSONGeometryCollection(
1018+
type= "GeometryCollection",
1019+
geometries = [shape.__geo_interface__
1020+
for shape in self
1021+
if shape is not None
1022+
],
1023+
)
10171024
return collection
10181025

10191026

1020-
class ShapeRecords(list):
1027+
class ShapeRecords(list[ShapeRecord]):
10211028
"""A class to hold a list of ShapeRecord objects. Subclasses list to ensure compatibility with
10221029
former work and to reuse all the optimizations of the builtin list.
10231030
In addition to the list interface, this also provides the GeoJSON __geo_interface__
@@ -1030,9 +1037,12 @@ def __repr__(self):
10301037
def __geo_interface__(self) -> GeoJSONFeatureCollection:
10311038
collection = {
10321039
"type": "FeatureCollection",
1033-
"features": [shaperec.__geo_interface__ for shaperec in self],
1040+
"features": [] #shaperec.__geo_interface__ for shaperec in self],
10341041
}
1035-
return collection
1042+
return GeoJSONFeatureCollection(
1043+
type="FeatureCollection",
1044+
features=[shaperec.__geo_interface__ for shaperec in self],
1045+
)
10361046

10371047

10381048
class ShapefileException(Exception):
@@ -1349,10 +1359,12 @@ def __iter__(self):
13491359
yield from self.iterShapeRecords()
13501360

13511361
@property
1352-
def __geo_interface__(self) -> GeoJSONFeatureCollection:
1362+
def __geo_interface__(self) -> GeoJSONFeatureCollectionWithBBox:
13531363
shaperecords = self.shapeRecords()
1354-
fcollection = shaperecords.__geo_interface__
1355-
fcollection["bbox"] = list(self.bbox)
1364+
fcollection = GeoJSONFeatureCollectionWithBBox(
1365+
bbox = list(self.bbox),
1366+
**shaperecords.__geo_interface__,
1367+
)
13561368
return fcollection
13571369

13581370
@property

0 commit comments

Comments
 (0)