pyogrio 0.12.0__cp314-cp314t-macosx_12_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyogrio/.dylibs/libgdal.37.3.11.4.dylib +0 -0
- pyogrio/__init__.py +57 -0
- pyogrio/_compat.py +54 -0
- pyogrio/_env.py +59 -0
- pyogrio/_err.cpython-314t-darwin.so +0 -0
- pyogrio/_geometry.cpython-314t-darwin.so +0 -0
- pyogrio/_io.cpython-314t-darwin.so +0 -0
- pyogrio/_ogr.cpython-314t-darwin.so +0 -0
- pyogrio/_version.py +21 -0
- pyogrio/_vsi.cpython-314t-darwin.so +0 -0
- pyogrio/core.py +387 -0
- pyogrio/errors.py +25 -0
- pyogrio/gdal_data/GDAL-targets-release.cmake +19 -0
- pyogrio/gdal_data/GDAL-targets.cmake +106 -0
- pyogrio/gdal_data/GDALConfig.cmake +24 -0
- pyogrio/gdal_data/GDALConfigVersion.cmake +65 -0
- pyogrio/gdal_data/GDALLogoBW.svg +138 -0
- pyogrio/gdal_data/GDALLogoColor.svg +126 -0
- pyogrio/gdal_data/GDALLogoGS.svg +126 -0
- pyogrio/gdal_data/LICENSE.TXT +467 -0
- pyogrio/gdal_data/MM_m_idofic.csv +321 -0
- pyogrio/gdal_data/copyright +467 -0
- pyogrio/gdal_data/cubewerx_extra.wkt +48 -0
- pyogrio/gdal_data/default.rsc +0 -0
- pyogrio/gdal_data/ecw_cs.wkt +1453 -0
- pyogrio/gdal_data/eedaconf.json +23 -0
- pyogrio/gdal_data/epsg.wkt +1 -0
- pyogrio/gdal_data/esri_StatePlane_extra.wkt +631 -0
- pyogrio/gdal_data/gdal_algorithm.schema.json +220 -0
- pyogrio/gdal_data/gdalg.schema.json +36 -0
- pyogrio/gdal_data/gdalicon.png +0 -0
- pyogrio/gdal_data/gdalinfo_output.schema.json +390 -0
- pyogrio/gdal_data/gdalmdiminfo_output.schema.json +326 -0
- pyogrio/gdal_data/gdaltileindex.xsd +253 -0
- pyogrio/gdal_data/gdalvrt.xsd +927 -0
- pyogrio/gdal_data/gfs.xsd +246 -0
- pyogrio/gdal_data/gml_registry.xml +117 -0
- pyogrio/gdal_data/gml_registry.xsd +66 -0
- pyogrio/gdal_data/grib2_center.csv +251 -0
- pyogrio/gdal_data/grib2_process.csv +102 -0
- pyogrio/gdal_data/grib2_subcenter.csv +63 -0
- pyogrio/gdal_data/grib2_table_4_2_0_0.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_0_1.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_0_13.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_0_14.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_0_15.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_0_16.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_0_17.csv +11 -0
- pyogrio/gdal_data/grib2_table_4_2_0_18.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_0_19.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_0_190.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_0_191.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_0_2.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_0_20.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_0_21.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_0_3.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_0_4.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_0_5.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_0_6.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_0_7.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_10_0.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_10_1.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_10_191.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_10_2.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_10_3.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_10_4.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_1_0.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_1_1.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_1_2.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_20_0.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_20_1.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_20_2.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_2_0.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_2_3.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_2_4.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_2_5.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_2_6.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_3_0.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_3_1.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_3_2.csv +28 -0
- pyogrio/gdal_data/grib2_table_4_2_3_3.csv +8 -0
- pyogrio/gdal_data/grib2_table_4_2_3_4.csv +14 -0
- pyogrio/gdal_data/grib2_table_4_2_3_5.csv +11 -0
- pyogrio/gdal_data/grib2_table_4_2_3_6.csv +11 -0
- pyogrio/gdal_data/grib2_table_4_2_4_0.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_4_1.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_4_10.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_4_2.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_4_3.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_4_4.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_4_5.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_4_6.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_4_7.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_4_8.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_4_9.csv +261 -0
- pyogrio/gdal_data/grib2_table_4_2_local_Canada.csv +5 -0
- pyogrio/gdal_data/grib2_table_4_2_local_HPC.csv +2 -0
- pyogrio/gdal_data/grib2_table_4_2_local_MRMS.csv +175 -0
- pyogrio/gdal_data/grib2_table_4_2_local_NCEP.csv +401 -0
- pyogrio/gdal_data/grib2_table_4_2_local_NDFD.csv +38 -0
- pyogrio/gdal_data/grib2_table_4_2_local_index.csv +7 -0
- pyogrio/gdal_data/grib2_table_4_5.csv +261 -0
- pyogrio/gdal_data/grib2_table_versions.csv +3 -0
- pyogrio/gdal_data/gt_datum.csv +229 -0
- pyogrio/gdal_data/gt_ellips.csv +24 -0
- pyogrio/gdal_data/header.dxf +1124 -0
- pyogrio/gdal_data/inspire_cp_BasicPropertyUnit.gfs +57 -0
- pyogrio/gdal_data/inspire_cp_CadastralBoundary.gfs +60 -0
- pyogrio/gdal_data/inspire_cp_CadastralParcel.gfs +81 -0
- pyogrio/gdal_data/inspire_cp_CadastralZoning.gfs +161 -0
- pyogrio/gdal_data/jpfgdgml_AdmArea.gfs +59 -0
- pyogrio/gdal_data/jpfgdgml_AdmBdry.gfs +49 -0
- pyogrio/gdal_data/jpfgdgml_AdmPt.gfs +59 -0
- pyogrio/gdal_data/jpfgdgml_BldA.gfs +54 -0
- pyogrio/gdal_data/jpfgdgml_BldL.gfs +54 -0
- pyogrio/gdal_data/jpfgdgml_Cntr.gfs +54 -0
- pyogrio/gdal_data/jpfgdgml_CommBdry.gfs +49 -0
- pyogrio/gdal_data/jpfgdgml_CommPt.gfs +59 -0
- pyogrio/gdal_data/jpfgdgml_Cstline.gfs +54 -0
- pyogrio/gdal_data/jpfgdgml_ElevPt.gfs +54 -0
- pyogrio/gdal_data/jpfgdgml_GCP.gfs +94 -0
- pyogrio/gdal_data/jpfgdgml_LeveeEdge.gfs +49 -0
- pyogrio/gdal_data/jpfgdgml_RailCL.gfs +54 -0
- pyogrio/gdal_data/jpfgdgml_RdASL.gfs +44 -0
- pyogrio/gdal_data/jpfgdgml_RdArea.gfs +54 -0
- pyogrio/gdal_data/jpfgdgml_RdCompt.gfs +59 -0
- pyogrio/gdal_data/jpfgdgml_RdEdg.gfs +59 -0
- pyogrio/gdal_data/jpfgdgml_RdMgtBdry.gfs +49 -0
- pyogrio/gdal_data/jpfgdgml_RdSgmtA.gfs +59 -0
- pyogrio/gdal_data/jpfgdgml_RvrMgtBdry.gfs +49 -0
- pyogrio/gdal_data/jpfgdgml_SBAPt.gfs +49 -0
- pyogrio/gdal_data/jpfgdgml_SBArea.gfs +54 -0
- pyogrio/gdal_data/jpfgdgml_SBBdry.gfs +44 -0
- pyogrio/gdal_data/jpfgdgml_WA.gfs +54 -0
- pyogrio/gdal_data/jpfgdgml_WL.gfs +54 -0
- pyogrio/gdal_data/jpfgdgml_WStrA.gfs +54 -0
- pyogrio/gdal_data/jpfgdgml_WStrL.gfs +54 -0
- pyogrio/gdal_data/leaflet_template.html +102 -0
- pyogrio/gdal_data/nitf_spec.xml +3288 -0
- pyogrio/gdal_data/nitf_spec.xsd +171 -0
- pyogrio/gdal_data/ogr_fields_override.schema.json +125 -0
- pyogrio/gdal_data/ogrinfo_output.schema.json +528 -0
- pyogrio/gdal_data/ogrvrt.xsd +528 -0
- pyogrio/gdal_data/osmconf.ini +134 -0
- pyogrio/gdal_data/ozi_datum.csv +131 -0
- pyogrio/gdal_data/ozi_ellips.csv +35 -0
- pyogrio/gdal_data/pci_datum.txt +530 -0
- pyogrio/gdal_data/pci_ellips.txt +129 -0
- pyogrio/gdal_data/pdfcomposition.xsd +703 -0
- pyogrio/gdal_data/pds4_template.xml +65 -0
- pyogrio/gdal_data/plscenesconf.json +1985 -0
- pyogrio/gdal_data/ruian_vf_ob_v1.gfs +1455 -0
- pyogrio/gdal_data/ruian_vf_st_uvoh_v1.gfs +86 -0
- pyogrio/gdal_data/ruian_vf_st_v1.gfs +1489 -0
- pyogrio/gdal_data/ruian_vf_v1.gfs +2126 -0
- pyogrio/gdal_data/s57agencies.csv +249 -0
- pyogrio/gdal_data/s57attributes.csv +484 -0
- pyogrio/gdal_data/s57expectedinput.csv +1008 -0
- pyogrio/gdal_data/s57objectclasses.csv +287 -0
- pyogrio/gdal_data/seed_2d.dgn +0 -0
- pyogrio/gdal_data/seed_3d.dgn +0 -0
- pyogrio/gdal_data/stateplane.csv +259 -0
- pyogrio/gdal_data/template_tiles.mapml +28 -0
- pyogrio/gdal_data/tms_LINZAntarticaMapTileGrid.json +190 -0
- pyogrio/gdal_data/tms_MapML_APSTILE.json +268 -0
- pyogrio/gdal_data/tms_MapML_CBMTILE.json +346 -0
- pyogrio/gdal_data/tms_NZTM2000.json +243 -0
- pyogrio/gdal_data/trailer.dxf +434 -0
- pyogrio/gdal_data/usage +4 -0
- pyogrio/gdal_data/vcpkg-cmake-wrapper.cmake +23 -0
- pyogrio/gdal_data/vcpkg.spdx.json +291 -0
- pyogrio/gdal_data/vcpkg_abi_info.txt +45 -0
- pyogrio/gdal_data/vdv452.xml +349 -0
- pyogrio/gdal_data/vdv452.xsd +45 -0
- pyogrio/gdal_data/vicar.json +164 -0
- pyogrio/geopandas.py +978 -0
- pyogrio/proj_data/CH +22 -0
- pyogrio/proj_data/GL27 +23 -0
- pyogrio/proj_data/ITRF2000 +24 -0
- pyogrio/proj_data/ITRF2008 +94 -0
- pyogrio/proj_data/ITRF2014 +55 -0
- pyogrio/proj_data/ITRF2020 +91 -0
- pyogrio/proj_data/copyright +34 -0
- pyogrio/proj_data/deformation_model.schema.json +582 -0
- pyogrio/proj_data/nad.lst +142 -0
- pyogrio/proj_data/nad27 +810 -0
- pyogrio/proj_data/nad83 +745 -0
- pyogrio/proj_data/other.extra +53 -0
- pyogrio/proj_data/proj-config-version.cmake +44 -0
- pyogrio/proj_data/proj-config.cmake +79 -0
- pyogrio/proj_data/proj-targets-release.cmake +19 -0
- pyogrio/proj_data/proj-targets.cmake +107 -0
- pyogrio/proj_data/proj.db +0 -0
- pyogrio/proj_data/proj.ini +59 -0
- pyogrio/proj_data/proj4-targets-release.cmake +19 -0
- pyogrio/proj_data/proj4-targets.cmake +107 -0
- pyogrio/proj_data/projjson.schema.json +1174 -0
- pyogrio/proj_data/triangulation.schema.json +214 -0
- pyogrio/proj_data/usage +9 -0
- pyogrio/proj_data/vcpkg.spdx.json +203 -0
- pyogrio/proj_data/vcpkg_abi_info.txt +28 -0
- pyogrio/proj_data/world +214 -0
- pyogrio/raw.py +897 -0
- pyogrio/tests/__init__.py +0 -0
- pyogrio/tests/conftest.py +588 -0
- pyogrio/tests/fixtures/README.md +108 -0
- pyogrio/tests/fixtures/curve.gpkg +0 -0
- pyogrio/tests/fixtures/curvepolygon.gpkg +0 -0
- pyogrio/tests/fixtures/line_zm.gpkg +0 -0
- pyogrio/tests/fixtures/list_field_values_file.parquet +0 -0
- pyogrio/tests/fixtures/list_nested_struct_file.parquet +0 -0
- pyogrio/tests/fixtures/multisurface.gpkg +0 -0
- pyogrio/tests/fixtures/naturalearth_lowres/naturalearth_lowres.cpg +1 -0
- pyogrio/tests/fixtures/naturalearth_lowres/naturalearth_lowres.dbf +0 -0
- pyogrio/tests/fixtures/naturalearth_lowres/naturalearth_lowres.prj +1 -0
- pyogrio/tests/fixtures/naturalearth_lowres/naturalearth_lowres.shp +0 -0
- pyogrio/tests/fixtures/naturalearth_lowres/naturalearth_lowres.shx +0 -0
- pyogrio/tests/fixtures/sample.osm.pbf +0 -0
- pyogrio/tests/fixtures/test_gpkg_nulls.gpkg +0 -0
- pyogrio/tests/test_arrow.py +1160 -0
- pyogrio/tests/test_core.py +702 -0
- pyogrio/tests/test_geopandas_io.py +3218 -0
- pyogrio/tests/test_path.py +374 -0
- pyogrio/tests/test_raw_io.py +1473 -0
- pyogrio/tests/test_util.py +56 -0
- pyogrio/util.py +258 -0
- pyogrio-0.12.0.dist-info/METADATA +125 -0
- pyogrio-0.12.0.dist-info/RECORD +231 -0
- pyogrio-0.12.0.dist-info/WHEEL +6 -0
- pyogrio-0.12.0.dist-info/licenses/LICENSE +21 -0
- pyogrio-0.12.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from pyogrio import vsi_listtree, vsi_unlink
|
|
4
|
+
from pyogrio.raw import read, write
|
|
5
|
+
from pyogrio.util import vsimem_rmtree_toplevel
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_vsimem_rmtree_toplevel(naturalearth_lowres):
|
|
11
|
+
# Prepare test data in /vsimem/
|
|
12
|
+
meta, _, geometry, field_data = read(naturalearth_lowres)
|
|
13
|
+
meta["spatial_index"] = False
|
|
14
|
+
meta["geometry_type"] = "MultiPolygon"
|
|
15
|
+
test_dir_path = Path(f"/vsimem/test/{naturalearth_lowres.stem}.gpkg")
|
|
16
|
+
test_dir2_path = Path(f"/vsimem/test2/test2/{naturalearth_lowres.stem}.gpkg")
|
|
17
|
+
|
|
18
|
+
write(test_dir_path, geometry, field_data, **meta)
|
|
19
|
+
write(test_dir2_path, geometry, field_data, **meta)
|
|
20
|
+
|
|
21
|
+
# Check if everything was created properly with listtree
|
|
22
|
+
files = vsi_listtree("/vsimem/")
|
|
23
|
+
assert test_dir_path.as_posix() in files
|
|
24
|
+
assert test_dir2_path.as_posix() in files
|
|
25
|
+
|
|
26
|
+
# Test deleting parent dir of file in single directory
|
|
27
|
+
vsimem_rmtree_toplevel(test_dir_path)
|
|
28
|
+
files = vsi_listtree("/vsimem/")
|
|
29
|
+
assert test_dir_path.parent.as_posix() not in files
|
|
30
|
+
assert test_dir2_path.as_posix() in files
|
|
31
|
+
|
|
32
|
+
# Test deleting top-level dir of file in a subdirectory
|
|
33
|
+
vsimem_rmtree_toplevel(test_dir2_path)
|
|
34
|
+
assert test_dir2_path.as_posix() not in vsi_listtree("/vsimem/")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_vsimem_rmtree_toplevel_error(naturalearth_lowres):
|
|
38
|
+
# Prepare test data in /vsimem
|
|
39
|
+
meta, _, geometry, field_data = read(naturalearth_lowres)
|
|
40
|
+
meta["spatial_index"] = False
|
|
41
|
+
meta["geometry_type"] = "MultiPolygon"
|
|
42
|
+
test_file_path = Path(f"/vsimem/pyogrio_test_{naturalearth_lowres.stem}.gpkg")
|
|
43
|
+
|
|
44
|
+
write(test_file_path, geometry, field_data, **meta)
|
|
45
|
+
assert test_file_path.as_posix() in vsi_listtree("/vsimem/")
|
|
46
|
+
|
|
47
|
+
# Deleting parent dir of non-existent file should raise an error.
|
|
48
|
+
with pytest.raises(FileNotFoundError, match="Path does not exist"):
|
|
49
|
+
vsimem_rmtree_toplevel("/vsimem/test/non-existent.gpkg")
|
|
50
|
+
|
|
51
|
+
# File should still be there
|
|
52
|
+
assert test_file_path.as_posix() in vsi_listtree("/vsimem/")
|
|
53
|
+
|
|
54
|
+
# Cleanup.
|
|
55
|
+
vsi_unlink(test_file_path)
|
|
56
|
+
assert test_file_path not in vsi_listtree("/vsimem/")
|
pyogrio/util.py
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"""Utility functions."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
import sys
|
|
5
|
+
from packaging.version import Version
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from urllib.parse import urlparse
|
|
8
|
+
|
|
9
|
+
from pyogrio._ogr import MULTI_EXTENSIONS
|
|
10
|
+
from pyogrio._vsi import vsimem_rmtree_toplevel as _vsimem_rmtree_toplevel
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_vsi_path_or_buffer(path_or_buffer):
|
|
14
|
+
"""Get VSI-prefixed path or bytes buffer depending on type of path_or_buffer.
|
|
15
|
+
|
|
16
|
+
If path_or_buffer is a bytes object, it will be returned directly and will
|
|
17
|
+
be read into an in-memory dataset when passed to one of the Cython functions.
|
|
18
|
+
|
|
19
|
+
If path_or_buffer is a file-like object with a read method, bytes will be
|
|
20
|
+
read from the file-like object and returned.
|
|
21
|
+
|
|
22
|
+
Otherwise, it will be converted to a string, and parsed to prefix with
|
|
23
|
+
appropriate GDAL /vsi*/ prefixes.
|
|
24
|
+
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
path_or_buffer : str, pathlib.Path, bytes, or file-like
|
|
28
|
+
A dataset path or URI, raw buffer, or file-like object with a read method.
|
|
29
|
+
|
|
30
|
+
Returns
|
|
31
|
+
-------
|
|
32
|
+
str or bytes
|
|
33
|
+
|
|
34
|
+
"""
|
|
35
|
+
# treat Path objects here already to ignore their read method + to avoid backslashes
|
|
36
|
+
# on Windows.
|
|
37
|
+
if isinstance(path_or_buffer, Path):
|
|
38
|
+
return vsi_path(path_or_buffer)
|
|
39
|
+
|
|
40
|
+
if isinstance(path_or_buffer, bytes):
|
|
41
|
+
return path_or_buffer
|
|
42
|
+
|
|
43
|
+
if hasattr(path_or_buffer, "read"):
|
|
44
|
+
bytes_buffer = path_or_buffer.read()
|
|
45
|
+
|
|
46
|
+
# rewind buffer if possible so that subsequent operations do not need to rewind
|
|
47
|
+
if hasattr(path_or_buffer, "seekable") and path_or_buffer.seekable():
|
|
48
|
+
path_or_buffer.seek(0)
|
|
49
|
+
|
|
50
|
+
return bytes_buffer
|
|
51
|
+
|
|
52
|
+
return vsi_path(str(path_or_buffer))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def vsi_path(path: str | Path) -> str:
|
|
56
|
+
"""Ensure path is a local path or a GDAL-compatible VSI path."""
|
|
57
|
+
# Convert Path objects to string, but for VSI paths, keep posix style path.
|
|
58
|
+
if isinstance(path, Path):
|
|
59
|
+
if sys.platform == "win32" and path.as_posix().startswith("/vsi"):
|
|
60
|
+
path = path.as_posix()
|
|
61
|
+
else:
|
|
62
|
+
path = str(path)
|
|
63
|
+
|
|
64
|
+
# path is already in GDAL format
|
|
65
|
+
if path.startswith("/vsi"):
|
|
66
|
+
return path
|
|
67
|
+
|
|
68
|
+
# Windows drive letters (e.g. "C:\") confuse `urlparse` as they look like
|
|
69
|
+
# URL schemes
|
|
70
|
+
if sys.platform == "win32" and re.match("^[a-zA-Z]\\:", path):
|
|
71
|
+
# If it is not a zip file or it is multi-extension zip file that is directly
|
|
72
|
+
# supported by a GDAL driver, return the path as is.
|
|
73
|
+
if not path.split("!")[0].endswith(".zip"):
|
|
74
|
+
return path
|
|
75
|
+
if path.split("!")[0].endswith(MULTI_EXTENSIONS):
|
|
76
|
+
return path
|
|
77
|
+
|
|
78
|
+
# prefix then allow to proceed with remaining parsing
|
|
79
|
+
path = f"zip://{path}"
|
|
80
|
+
|
|
81
|
+
path, archive, scheme = _parse_uri(path)
|
|
82
|
+
|
|
83
|
+
if (
|
|
84
|
+
scheme
|
|
85
|
+
or archive
|
|
86
|
+
or (path.endswith(".zip") and not path.endswith(MULTI_EXTENSIONS))
|
|
87
|
+
):
|
|
88
|
+
return _construct_vsi_path(path, archive, scheme)
|
|
89
|
+
|
|
90
|
+
return path
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# Supported URI schemes and their mapping to GDAL's VSI suffix.
|
|
94
|
+
SCHEMES = {
|
|
95
|
+
"file": "file",
|
|
96
|
+
"zip": "zip",
|
|
97
|
+
"tar": "tar",
|
|
98
|
+
"gzip": "gzip",
|
|
99
|
+
"http": "curl",
|
|
100
|
+
"https": "curl",
|
|
101
|
+
"ftp": "curl",
|
|
102
|
+
"s3": "s3",
|
|
103
|
+
"gs": "gs",
|
|
104
|
+
"az": "az",
|
|
105
|
+
"adls": "adls",
|
|
106
|
+
"adl": "adls", # fsspec uses this
|
|
107
|
+
"hdfs": "hdfs",
|
|
108
|
+
"webhdfs": "webhdfs",
|
|
109
|
+
# GDAL additionally supports oss and swift for remote filesystems, but
|
|
110
|
+
# those are for now not added as supported URI
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
CURLSCHEMES = {k for k, v in SCHEMES.items() if v == "curl"}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _parse_uri(path: str):
|
|
117
|
+
"""Parse a URI.
|
|
118
|
+
|
|
119
|
+
Returns a tuples of (path, archive, scheme)
|
|
120
|
+
|
|
121
|
+
path : str
|
|
122
|
+
Parsed path. Includes the hostname and query string in the case
|
|
123
|
+
of a URI.
|
|
124
|
+
archive : str
|
|
125
|
+
Parsed archive path.
|
|
126
|
+
scheme : str
|
|
127
|
+
URI scheme such as "https" or "zip+s3".
|
|
128
|
+
"""
|
|
129
|
+
parts = urlparse(path, allow_fragments=False)
|
|
130
|
+
|
|
131
|
+
# if the scheme is not one of GDAL's supported schemes, return raw path
|
|
132
|
+
if parts.scheme and not all(p in SCHEMES for p in parts.scheme.split("+")):
|
|
133
|
+
return path, "", ""
|
|
134
|
+
|
|
135
|
+
# we have a URI
|
|
136
|
+
path = parts.path
|
|
137
|
+
scheme = parts.scheme or ""
|
|
138
|
+
|
|
139
|
+
if parts.query:
|
|
140
|
+
path += "?" + parts.query
|
|
141
|
+
|
|
142
|
+
if parts.scheme and parts.netloc:
|
|
143
|
+
path = parts.netloc + path
|
|
144
|
+
|
|
145
|
+
parts = path.split("!")
|
|
146
|
+
path = parts.pop() if parts else ""
|
|
147
|
+
archive = parts.pop() if parts else ""
|
|
148
|
+
return (path, archive, scheme)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _construct_vsi_path(path, archive, scheme) -> str:
|
|
152
|
+
"""Convert a parsed path to a GDAL VSI path."""
|
|
153
|
+
prefix = ""
|
|
154
|
+
suffix = ""
|
|
155
|
+
schemes = scheme.split("+")
|
|
156
|
+
|
|
157
|
+
if "zip" not in schemes and (
|
|
158
|
+
archive.endswith(".zip")
|
|
159
|
+
or (path.endswith(".zip") and not path.endswith(MULTI_EXTENSIONS))
|
|
160
|
+
):
|
|
161
|
+
schemes.insert(0, "zip")
|
|
162
|
+
|
|
163
|
+
if schemes:
|
|
164
|
+
prefix = "/".join(f"vsi{SCHEMES[p]}" for p in schemes if p and p != "file")
|
|
165
|
+
|
|
166
|
+
if schemes[-1] in CURLSCHEMES:
|
|
167
|
+
suffix = f"{schemes[-1]}://"
|
|
168
|
+
|
|
169
|
+
if prefix:
|
|
170
|
+
if archive:
|
|
171
|
+
return "/{}/{}{}/{}".format(prefix, suffix, archive, path.lstrip("/"))
|
|
172
|
+
else:
|
|
173
|
+
return f"/{prefix}/{suffix}{path}"
|
|
174
|
+
|
|
175
|
+
return path
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _preprocess_options_key_value(options):
|
|
179
|
+
"""Preprocess options.
|
|
180
|
+
|
|
181
|
+
For example, `spatial_index=True` gets converted to `SPATIAL_INDEX="YES"`.
|
|
182
|
+
"""
|
|
183
|
+
if not isinstance(options, dict):
|
|
184
|
+
raise TypeError(f"Expected options to be a dict, got {type(options)}")
|
|
185
|
+
|
|
186
|
+
result = {}
|
|
187
|
+
for k, v in options.items():
|
|
188
|
+
if v is None:
|
|
189
|
+
continue
|
|
190
|
+
k = k.upper()
|
|
191
|
+
if isinstance(v, bool):
|
|
192
|
+
v = "ON" if v else "OFF"
|
|
193
|
+
else:
|
|
194
|
+
v = str(v)
|
|
195
|
+
result[k] = v
|
|
196
|
+
return result
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def _mask_to_wkb(mask):
|
|
200
|
+
"""Convert a Shapely mask geometry to WKB.
|
|
201
|
+
|
|
202
|
+
Parameters
|
|
203
|
+
----------
|
|
204
|
+
mask : Shapely geometry
|
|
205
|
+
The geometry to convert to WKB.
|
|
206
|
+
|
|
207
|
+
Returns
|
|
208
|
+
-------
|
|
209
|
+
WKB bytes or None
|
|
210
|
+
|
|
211
|
+
Raises
|
|
212
|
+
------
|
|
213
|
+
ValueError
|
|
214
|
+
raised if Shapely >= 2.0 is not available or mask is not a Shapely
|
|
215
|
+
Geometry object
|
|
216
|
+
|
|
217
|
+
"""
|
|
218
|
+
if mask is None:
|
|
219
|
+
return mask
|
|
220
|
+
|
|
221
|
+
try:
|
|
222
|
+
import shapely
|
|
223
|
+
|
|
224
|
+
if Version(shapely.__version__) < Version("2.0.0"):
|
|
225
|
+
shapely = None
|
|
226
|
+
except ImportError:
|
|
227
|
+
shapely = None
|
|
228
|
+
|
|
229
|
+
if not shapely:
|
|
230
|
+
raise ValueError("'mask' parameter requires Shapely >= 2.0")
|
|
231
|
+
|
|
232
|
+
if not isinstance(mask, shapely.Geometry):
|
|
233
|
+
raise ValueError("'mask' parameter must be a Shapely geometry")
|
|
234
|
+
|
|
235
|
+
return shapely.to_wkb(mask)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def vsimem_rmtree_toplevel(path: str | Path):
|
|
239
|
+
"""Remove the parent directory of the file path recursively.
|
|
240
|
+
|
|
241
|
+
This is used for final cleanup of an in-memory dataset, which may have been
|
|
242
|
+
created within a directory to contain sibling files.
|
|
243
|
+
|
|
244
|
+
Additional VSI handlers may be chained to the left of /vsimem/ in path and
|
|
245
|
+
will be ignored.
|
|
246
|
+
|
|
247
|
+
Remark: function is defined here to be able to run tests on it.
|
|
248
|
+
|
|
249
|
+
Parameters
|
|
250
|
+
----------
|
|
251
|
+
path : str or pathlib.Path
|
|
252
|
+
path to in-memory file
|
|
253
|
+
|
|
254
|
+
"""
|
|
255
|
+
if isinstance(path, Path):
|
|
256
|
+
path = path.as_posix()
|
|
257
|
+
|
|
258
|
+
_vsimem_rmtree_toplevel(path)
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyogrio
|
|
3
|
+
Version: 0.12.0
|
|
4
|
+
Summary: Vectorized spatial vector file format I/O using GDAL/OGR
|
|
5
|
+
Author: pyogrio contributors
|
|
6
|
+
Author-email: "Brendan C. Ward" <bcward@astutespruce.com>
|
|
7
|
+
Maintainer: pyogrio contributors
|
|
8
|
+
License: MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2020-2024 Brendan C. Ward and pyogrio contributors
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
|
29
|
+
|
|
30
|
+
Project-URL: Home, https://pyogrio.readthedocs.io/
|
|
31
|
+
Project-URL: Repository, https://github.com/geopandas/pyogrio
|
|
32
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
33
|
+
Classifier: Intended Audience :: Science/Research
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Operating System :: OS Independent
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
38
|
+
Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta
|
|
39
|
+
Requires-Python: >=3.10
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
License-File: LICENSE
|
|
42
|
+
Requires-Dist: certifi
|
|
43
|
+
Requires-Dist: numpy
|
|
44
|
+
Requires-Dist: packaging
|
|
45
|
+
Provides-Extra: dev
|
|
46
|
+
Requires-Dist: cython>=3.1; extra == "dev"
|
|
47
|
+
Provides-Extra: test
|
|
48
|
+
Requires-Dist: pytest; extra == "test"
|
|
49
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
50
|
+
Provides-Extra: benchmark
|
|
51
|
+
Requires-Dist: pytest-benchmark; extra == "benchmark"
|
|
52
|
+
Provides-Extra: geopandas
|
|
53
|
+
Requires-Dist: geopandas; extra == "geopandas"
|
|
54
|
+
Dynamic: license-file
|
|
55
|
+
|
|
56
|
+
# pyogrio - bulk-oriented spatial vector file I/O using GDAL/OGR
|
|
57
|
+
|
|
58
|
+
Pyogrio provides fast, bulk-oriented read and write access to
|
|
59
|
+
[GDAL/OGR](https://gdal.org/en/latest/drivers/vector/index.html) vector data
|
|
60
|
+
sources, such as ESRI Shapefile, GeoPackage, GeoJSON, and several others.
|
|
61
|
+
Vector data sources typically have geometries, such as points, lines, or
|
|
62
|
+
polygons, and associated records with potentially many columns worth of data.
|
|
63
|
+
|
|
64
|
+
The typical use is to read or write these data sources to/from
|
|
65
|
+
[GeoPandas](https://github.com/geopandas/geopandas) `GeoDataFrames`. Because
|
|
66
|
+
the geometry column is optional, reading or writing only non-spatial data is
|
|
67
|
+
also possible. Hence, GeoPackage attribute tables, DBF files, or CSV files are
|
|
68
|
+
also supported.
|
|
69
|
+
|
|
70
|
+
Pyogrio is fast because it uses pre-compiled bindings for GDAL/OGR to read and
|
|
71
|
+
write the data records in bulk. This approach avoids multiple steps of
|
|
72
|
+
converting to and from Python data types within Python, so performance becomes
|
|
73
|
+
primarily limited by the underlying I/O speed of data source drivers in
|
|
74
|
+
GDAL/OGR.
|
|
75
|
+
|
|
76
|
+
We have seen \>5-10x speedups reading files and \>5-20x speedups writing files
|
|
77
|
+
compared to using row-per-row approaches (e.g. Fiona).
|
|
78
|
+
|
|
79
|
+
Read the documentation for more information:
|
|
80
|
+
[https://pyogrio.readthedocs.io](https://pyogrio.readthedocs.io/en/latest/).
|
|
81
|
+
|
|
82
|
+
## Requirements
|
|
83
|
+
|
|
84
|
+
Supports Python 3.10 - 3.14 and GDAL 3.6.x - 3.11.x.
|
|
85
|
+
|
|
86
|
+
Reading to GeoDataFrames requires `geopandas>=0.12` with `shapely>=2`.
|
|
87
|
+
|
|
88
|
+
Additionally, installing `pyarrow` in combination with GDAL 3.6+ enables
|
|
89
|
+
a further speed-up when specifying `use_arrow=True`.
|
|
90
|
+
|
|
91
|
+
## Installation
|
|
92
|
+
|
|
93
|
+
Pyogrio is currently available on
|
|
94
|
+
[conda-forge](https://anaconda.org/conda-forge/pyogrio)
|
|
95
|
+
and [PyPI](https://pypi.org/project/pyogrio/)
|
|
96
|
+
for Linux, MacOS, and Windows.
|
|
97
|
+
|
|
98
|
+
Please read the
|
|
99
|
+
[installation documentation](https://pyogrio.readthedocs.io/en/latest/install.html)
|
|
100
|
+
for more information.
|
|
101
|
+
|
|
102
|
+
## Supported vector formats
|
|
103
|
+
|
|
104
|
+
Pyogrio supports most common vector data source formats (provided they are also
|
|
105
|
+
supported by GDAL/OGR), including ESRI Shapefile, GeoPackage, GeoJSON, and
|
|
106
|
+
FlatGeobuf.
|
|
107
|
+
|
|
108
|
+
Please see the [list of supported formats](https://pyogrio.readthedocs.io/en/latest/supported_formats.html)
|
|
109
|
+
for more information.
|
|
110
|
+
|
|
111
|
+
## Getting started
|
|
112
|
+
|
|
113
|
+
Please read the [introduction](https://pyogrio.readthedocs.io/en/latest/supported_formats.html)
|
|
114
|
+
for more information and examples to get started using Pyogrio.
|
|
115
|
+
|
|
116
|
+
You can also check out the [API documentation](https://pyogrio.readthedocs.io/en/latest/api.html)
|
|
117
|
+
for full details on using the API.
|
|
118
|
+
|
|
119
|
+
## Credits
|
|
120
|
+
|
|
121
|
+
This project is made possible by the tremendous efforts of the GDAL, Fiona, and
|
|
122
|
+
Geopandas communities.
|
|
123
|
+
|
|
124
|
+
- Core I/O methods and supporting functions adapted from [Fiona](https://github.com/Toblerity/Fiona)
|
|
125
|
+
- Inspired by [Fiona PR](https://github.com/Toblerity/Fiona/pull/540/files)
|