-
-
Notifications
You must be signed in to change notification settings - Fork 465
refactor: streamline geojson handling by centralizing file reading logic #1336
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
acdd5c7
8addfa1
dfaf34f
7d7bdd5
e21d77f
249fc83
0ca31e8
6cc4b87
de62864
d26e1ab
0a362f3
c6c432d
b30a270
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1516,11 +1516,15 @@ def kml_to_shp(in_kml, out_shp): | |
|
|
||
| check_package(name="geopandas", URL="https://geopandas.org") | ||
|
|
||
| import fiona | ||
| import geopandas as gpd | ||
|
|
||
| # print(fiona.supported_drivers) | ||
| fiona.drvsupport.supported_drivers["KML"] = "rw" | ||
| try: | ||
| import fiona | ||
|
|
||
| fiona.drvsupport.supported_drivers["KML"] = "rw" | ||
| except ImportError: | ||
| # fiona is optional; the default pyogrio engine reads KML natively. | ||
| pass | ||
| df = gpd.read_file(in_kml, driver="KML") | ||
| df.to_file(out_shp) | ||
|
|
||
|
|
@@ -1555,12 +1559,15 @@ def kml_to_geojson(in_kml, out_geojson=None): | |
|
|
||
| check_package(name="geopandas", URL="https://geopandas.org") | ||
|
|
||
| import fiona | ||
| import geopandas as gpd | ||
|
|
||
| # import fiona | ||
| # print(fiona.supported_drivers) | ||
| fiona.drvsupport.supported_drivers["KML"] = "rw" | ||
| try: | ||
| import fiona | ||
|
|
||
| fiona.drvsupport.supported_drivers["KML"] = "rw" | ||
| except ImportError: | ||
| # fiona is optional; the default pyogrio engine reads KML natively. | ||
| pass | ||
| gdf = gpd.read_file(in_kml, driver="KML") | ||
|
|
||
| if out_geojson is not None: | ||
|
|
@@ -1693,7 +1700,6 @@ def vector_to_geojson( | |
|
|
||
| warnings.filterwarnings("ignore") | ||
| check_package(name="geopandas", URL="https://geopandas.org") | ||
| import fiona | ||
| import geopandas as gpd | ||
|
|
||
| if not filename.startswith("http"): | ||
|
|
@@ -1702,7 +1708,13 @@ def vector_to_geojson( | |
| filename = "zip://" + filename | ||
| ext = os.path.splitext(filename)[1].lower() | ||
| if ext == ".kml": | ||
| fiona.drvsupport.supported_drivers["KML"] = "rw" | ||
| try: | ||
| import fiona | ||
|
|
||
| fiona.drvsupport.supported_drivers["KML"] = "rw" | ||
| except ImportError: | ||
| # fiona is optional; the default pyogrio engine reads KML natively. | ||
| pass | ||
| df = gpd.read_file( | ||
| filename, | ||
| bbox=bbox, | ||
|
|
@@ -3950,11 +3962,47 @@ def geojson_to_gdf(in_geojson, encoding="utf-8", **kwargs: Any): | |
| with open(out_file, "w") as f: | ||
| json.dump(in_geojson, f) | ||
| in_geojson = out_file | ||
| elif isinstance(in_geojson, str) and in_geojson.startswith("http"): | ||
| try: | ||
| return gpd.read_file(in_geojson, encoding=encoding, **kwargs) | ||
| except Exception: | ||
| response = requests.get(in_geojson, timeout=30) | ||
| response.raise_for_status() | ||
| data = response.json() | ||
| if isinstance(data, dict) and data.get("type") == "Feature": | ||
| return gpd.GeoDataFrame.from_features([data], **kwargs) | ||
| return gpd.GeoDataFrame.from_features(data, **kwargs) | ||
|
Comment on lines
+3965
to
+3974
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🌐 Web query:
💡 Result: No, geopandas.GeoDataFrame.from_features does not accept arbitrary keyword arguments [1][2]. The method signature is explicitly defined as Citations:
🏁 Script executed: python3 - <<'PY'
from pathlib import Path
path = Path("leafmap/common.py")
lines = path.read_text().splitlines()
start, end = 3935, 3970
for i in range(start, min(end, len(lines)) + 1):
print(f"{i:5d}: {lines[i-1]}")
PYRepository: opengeos/leafmap Length of output: 1778 Drop unsupported kwargs in the HTTP fallback. 🧰 Tools🪛 ast-grep (0.44.0)[warning] 3956-3956: Request-controlled URL passed to requests; validate against an allowlist to prevent SSRF. (ssrf-requests) 🪛 Ruff (0.15.20)[warning] 3956-3956: Do not catch blind exception: (BLE001) 🤖 Prompt for AI Agents |
||
|
|
||
| gdf = gpd.read_file(in_geojson, encoding=encoding, **kwargs) | ||
| return gdf | ||
|
|
||
|
|
||
| def sanitize_geojson(obj: Any) -> Any: | ||
| """Recursively converts NumPy types in a GeoJSON-like object to native Python types. | ||
|
|
||
| GeoDataFrame.__geo_interface__ can leave NumPy arrays/scalars in feature | ||
| properties (e.g. list-valued columns are read back as ndarrays), which are | ||
| not JSON serializable and break widget serialization. This makes the object | ||
| safe for ``json.dumps``. | ||
|
|
||
| Args: | ||
| obj (Any): A GeoJSON dict, list, or scalar that may contain NumPy types. | ||
|
|
||
| Returns: | ||
| Any: The same structure with NumPy arrays converted to lists and NumPy | ||
| scalars to native Python types. | ||
| """ | ||
| if isinstance(obj, np.ndarray): | ||
| return obj.tolist() | ||
| elif isinstance(obj, np.generic): | ||
| return obj.item() | ||
| elif isinstance(obj, dict): | ||
| return {key: sanitize_geojson(value) for key, value in obj.items()} | ||
| elif isinstance(obj, (list, tuple)): | ||
| return [sanitize_geojson(value) for value in obj] | ||
| return obj | ||
|
|
||
|
|
||
| def geojson_to_df(in_geojson, encoding="utf-8", drop_geometry=True): | ||
| """Converts a GeoJSON object to a pandas DataFrame. | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
Blind
except Exceptionswallows the original fetch/parse error.except Exception:(flagged by ruff BLE001) silently discards the failure reason from the initialgpd.read_fileattempt, making it hard to diagnose why the fallback path was triggered when the fallback itself later fails.♻️ Suggested improvement
📝 Committable suggestion
🧰 Tools
🪛 ast-grep (0.44.0)
[warning] 3956-3956: Request-controlled URL passed to requests; validate against an allowlist to prevent SSRF.
Context: requests.get(in_geojson, timeout=30)
Note: [CWE-918] Server-Side Request Forgery (SSRF).
(ssrf-requests)
🪛 Ruff (0.15.20)
[warning] 3956-3956: Do not catch blind exception:
Exception(BLE001)
🤖 Prompt for AI Agents
Source: Linters/SAST tools