From 6336e2dcc3ce3205351a9451e039e9ea108063e9 Mon Sep 17 00:00:00 2001 From: Hans Then Date: Sun, 21 Jan 2024 10:56:02 +0100 Subject: [PATCH] Geojson: allow null geometry objects (#1858) * GeoJson objects can have null geometry objects See https://datatracker.ietf.org/doc/html/rfc7946#section-3.2 A Feature object has a member with the name "geometry". The value of the geometry member SHALL be either a Geometry object as defined above or . . . a JSON null value. * Missed an instance geometry cannot be null * Handle empty geojson features --- folium/features.py | 9 +++++++-- folium/utilities.py | 14 +++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/folium/features.py b/folium/features.py index 041559b61..586ce2211 100644 --- a/folium/features.py +++ b/folium/features.py @@ -1148,7 +1148,8 @@ def warn_for_geometry_collections(self) -> None: geom_collections = [ feature.get("properties") if feature.get("properties") is not None else key for key, feature in enumerate(self._parent.data["features"]) - if feature["geometry"]["type"] == "GeometryCollection" + if feature["geometry"] + and feature["geometry"]["type"] == "GeometryCollection" ] if any(geom_collections): warnings.warn( @@ -1164,7 +1165,11 @@ def render(self, **kwargs) -> None: """Renders the HTML representation of the element.""" figure = self.get_root() if isinstance(self._parent, GeoJson): - keys = tuple(self._parent.data["features"][0]["properties"].keys()) + keys = tuple( + self._parent.data["features"][0]["properties"].keys() + if self._parent.data["features"] + else [] + ) self.warn_for_geometry_collections() elif isinstance(self._parent, TopoJson): obj_name = self._parent.object_path.split(".")[-1] diff --git a/folium/utilities.py b/folium/utilities.py index afc4fc531..7e9416a40 100644 --- a/folium/utilities.py +++ b/folium/utilities.py @@ -276,10 +276,18 @@ def iter_coords(obj: Any) -> Iterator[Tuple[float, ...]]: if isinstance(obj, (tuple, list)): coords = obj elif "features" in obj: - coords = [geom["geometry"]["coordinates"] for geom in obj["features"]] + coords = [ + geom["geometry"]["coordinates"] + for geom in obj["features"] + if geom["geometry"] + ] elif "geometry" in obj: - coords = obj["geometry"]["coordinates"] - elif "geometries" in obj and "coordinates" in obj["geometries"][0]: + coords = obj["geometry"]["coordinates"] if obj["geometry"] else [] + elif ( + "geometries" in obj + and obj["geometries"][0] + and "coordinates" in obj["geometries"][0] + ): coords = obj["geometries"][0]["coordinates"] else: coords = obj.get("coordinates", obj)