@@ -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
157157class 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
10381048class 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