from pathlib import Path from zipfile import ZipFile, ZIP_DEFLATED import pytest from pyogrio import ( __gdal_version_string__, __version__, list_drivers, ) from pyogrio._compat import HAS_ARROW_API, HAS_GDAL_GEOS, HAS_SHAPELY from pyogrio.raw import read, write _data_dir = Path(__file__).parent.resolve() / "fixtures" # mapping of driver extension to driver name for well-supported drivers DRIVERS = { ".fgb": "FlatGeobuf", ".geojson": "GeoJSON", ".geojsonl": "GeoJSONSeq", ".geojsons": "GeoJSONSeq", ".gpkg": "GPKG", ".shp": "ESRI Shapefile", } # mapping of driver name to extension DRIVER_EXT = {driver: ext for ext, driver in DRIVERS.items()} ALL_EXTS = [".fgb", ".geojson", ".geojsonl", ".gpkg", ".shp"] def pytest_report_header(config): drivers = ", ".join( f"{driver}({capability})" for driver, capability in sorted(list_drivers().items()) ) return ( f"pyogrio {__version__}\n" f"GDAL {__gdal_version_string__}\n" f"Supported drivers: {drivers}" ) # marks to skip tests if optional dependecies are not present requires_arrow_api = pytest.mark.skipif( not HAS_ARROW_API, reason="GDAL>=3.6 and pyarrow required" ) requires_gdal_geos = pytest.mark.skipif( not HAS_GDAL_GEOS, reason="GDAL compiled with GEOS required" ) requires_shapely = pytest.mark.skipif(not HAS_SHAPELY, reason="Shapely >= 2.0 required") def prepare_testfile(testfile_path, dst_dir, ext): if ext == testfile_path.suffix: return testfile_path dst_path = dst_dir / f"{testfile_path.stem}{ext}" if dst_path.exists(): return dst_path meta, _, geometry, field_data = read(testfile_path) if ext == ".fgb": # For .fgb, spatial_index=False to avoid the rows being reordered meta["spatial_index"] = False # allow mixed Polygons/MultiPolygons type meta["geometry_type"] = "Unknown" elif ext == ".gpkg": # For .gpkg, spatial_index=False to avoid the rows being reordered meta["spatial_index"] = False meta["geometry_type"] = "MultiPolygon" write(dst_path, geometry, field_data, **meta) return dst_path @pytest.fixture(scope="session") def data_dir(): return _data_dir @pytest.fixture(scope="function") def naturalearth_lowres(tmp_path, request): ext = getattr(request, "param", ".shp") testfile_path = _data_dir / Path("naturalearth_lowres/naturalearth_lowres.shp") return prepare_testfile(testfile_path, tmp_path, ext) @pytest.fixture(scope="function", params=ALL_EXTS) def naturalearth_lowres_all_ext(tmp_path, naturalearth_lowres, request): return prepare_testfile(naturalearth_lowres, tmp_path, request.param) @pytest.fixture(scope="function") def naturalearth_lowres_vsi(tmp_path, naturalearth_lowres): """Wrap naturalearth_lowres as a zip file for vsi tests""" path = tmp_path / f"{naturalearth_lowres.name}.zip" with ZipFile(path, mode="w", compression=ZIP_DEFLATED, compresslevel=5) as out: for ext in ["dbf", "prj", "shp", "shx"]: filename = f"{naturalearth_lowres.stem}.{ext}" out.write(naturalearth_lowres.parent / filename, filename) return path, f"/vsizip/{path}/{naturalearth_lowres.name}" @pytest.fixture(scope="session") def test_fgdb_vsi(): return f"/vsizip/{_data_dir}/test_fgdb.gdb.zip" @pytest.fixture(scope="session") def test_gpkg_nulls(): return _data_dir / "test_gpkg_nulls.gpkg" @pytest.fixture(scope="session") def test_ogr_types_list(): return _data_dir / "test_ogr_types_list.geojson" @pytest.fixture(scope="session") def test_datetime(): return _data_dir / "test_datetime.geojson" @pytest.fixture(scope="session") def test_datetime_tz(): return _data_dir / "test_datetime_tz.geojson"