pyogrio 0.9.0__cp311-cp311-manylinux_2_28_aarch64.whl → 0.11.0__cp311-cp311-manylinux_2_28_aarch64.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.

Potentially problematic release.


This version of pyogrio might be problematic. Click here for more details.

Files changed (86) hide show
  1. pyogrio/__init__.py +28 -21
  2. pyogrio/_compat.py +15 -1
  3. pyogrio/_env.py +4 -6
  4. pyogrio/_err.cpython-311-aarch64-linux-gnu.so +0 -0
  5. pyogrio/_geometry.cpython-311-aarch64-linux-gnu.so +0 -0
  6. pyogrio/_io.cpython-311-aarch64-linux-gnu.so +0 -0
  7. pyogrio/_ogr.cpython-311-aarch64-linux-gnu.so +0 -0
  8. pyogrio/_version.py +3 -3
  9. pyogrio/_vsi.cpython-311-aarch64-linux-gnu.so +0 -0
  10. pyogrio/core.py +86 -20
  11. pyogrio/errors.py +9 -16
  12. pyogrio/gdal_data/GDAL-targets-release.cmake +3 -3
  13. pyogrio/gdal_data/GDAL-targets.cmake +2 -2
  14. pyogrio/gdal_data/GDALConfig.cmake +0 -1
  15. pyogrio/gdal_data/GDALConfigVersion.cmake +3 -3
  16. pyogrio/gdal_data/MM_m_idofic.csv +321 -0
  17. pyogrio/gdal_data/gdalinfo_output.schema.json +3 -3
  18. pyogrio/gdal_data/gdaltileindex.xsd +253 -0
  19. pyogrio/gdal_data/gdalvrt.xsd +178 -63
  20. pyogrio/gdal_data/nitf_spec.xml +1 -17
  21. pyogrio/gdal_data/nitf_spec.xsd +1 -17
  22. pyogrio/gdal_data/ogrinfo_output.schema.json +23 -0
  23. pyogrio/gdal_data/ogrvrt.xsd +4 -17
  24. pyogrio/gdal_data/osmconf.ini +3 -1
  25. pyogrio/gdal_data/pci_datum.txt +222 -155
  26. pyogrio/gdal_data/pci_ellips.txt +90 -38
  27. pyogrio/gdal_data/pdfcomposition.xsd +1 -17
  28. pyogrio/gdal_data/vcpkg.spdx.json +32 -27
  29. pyogrio/gdal_data/vcpkg_abi_info.txt +30 -29
  30. pyogrio/gdal_data/vdv452.xml +1 -17
  31. pyogrio/gdal_data/vdv452.xsd +1 -17
  32. pyogrio/geopandas.py +122 -66
  33. pyogrio/proj_data/ITRF2014 +1 -1
  34. pyogrio/proj_data/ITRF2020 +91 -0
  35. pyogrio/proj_data/proj-config-version.cmake +2 -2
  36. pyogrio/proj_data/proj-config.cmake +1 -1
  37. pyogrio/proj_data/proj-targets.cmake +3 -3
  38. pyogrio/proj_data/proj.db +0 -0
  39. pyogrio/proj_data/proj.ini +11 -3
  40. pyogrio/proj_data/proj4-targets.cmake +3 -3
  41. pyogrio/proj_data/projjson.schema.json +1 -1
  42. pyogrio/proj_data/usage +7 -2
  43. pyogrio/proj_data/vcpkg.spdx.json +27 -22
  44. pyogrio/proj_data/vcpkg_abi_info.txt +17 -16
  45. pyogrio/raw.py +46 -30
  46. pyogrio/tests/conftest.py +214 -12
  47. pyogrio/tests/fixtures/README.md +32 -13
  48. pyogrio/tests/fixtures/curve.gpkg +0 -0
  49. pyogrio/tests/fixtures/{test_multisurface.gpkg → curvepolygon.gpkg} +0 -0
  50. pyogrio/tests/fixtures/line_zm.gpkg +0 -0
  51. pyogrio/tests/fixtures/multisurface.gpkg +0 -0
  52. pyogrio/tests/test_arrow.py +181 -24
  53. pyogrio/tests/test_core.py +170 -76
  54. pyogrio/tests/test_geopandas_io.py +483 -135
  55. pyogrio/tests/test_path.py +39 -17
  56. pyogrio/tests/test_raw_io.py +170 -55
  57. pyogrio/tests/test_util.py +56 -0
  58. pyogrio/util.py +69 -32
  59. pyogrio-0.11.0.dist-info/METADATA +124 -0
  60. {pyogrio-0.9.0.dist-info → pyogrio-0.11.0.dist-info}/RECORD +200 -214
  61. {pyogrio-0.9.0.dist-info → pyogrio-0.11.0.dist-info}/WHEEL +1 -1
  62. {pyogrio-0.9.0.dist-info → pyogrio-0.11.0.dist-info/licenses}/LICENSE +1 -1
  63. pyogrio.libs/{libgdal-6ff0914e.so.34.3.8.5 → libgdal-4bc0d15f.so.36.3.10.3} +0 -0
  64. pyogrio/_err.pxd +0 -4
  65. pyogrio/_err.pyx +0 -250
  66. pyogrio/_geometry.pxd +0 -4
  67. pyogrio/_geometry.pyx +0 -129
  68. pyogrio/_io.pxd +0 -0
  69. pyogrio/_io.pyx +0 -2742
  70. pyogrio/_ogr.pxd +0 -444
  71. pyogrio/_ogr.pyx +0 -346
  72. pyogrio/_vsi.pxd +0 -4
  73. pyogrio/_vsi.pyx +0 -140
  74. pyogrio/arrow_bridge.h +0 -115
  75. pyogrio/gdal_data/bag_template.xml +0 -201
  76. pyogrio/gdal_data/gmlasconf.xml +0 -169
  77. pyogrio/gdal_data/gmlasconf.xsd +0 -1066
  78. pyogrio/gdal_data/netcdf_config.xsd +0 -143
  79. pyogrio/tests/fixtures/poly_not_enough_points.shp.zip +0 -0
  80. pyogrio/tests/fixtures/test_datetime.geojson +0 -7
  81. pyogrio/tests/fixtures/test_datetime_tz.geojson +0 -8
  82. pyogrio/tests/fixtures/test_fgdb.gdb.zip +0 -0
  83. pyogrio/tests/fixtures/test_nested.geojson +0 -18
  84. pyogrio/tests/fixtures/test_ogr_types_list.geojson +0 -12
  85. pyogrio-0.9.0.dist-info/METADATA +0 -100
  86. {pyogrio-0.9.0.dist-info → pyogrio-0.11.0.dist-info}/top_level.txt +0 -0
@@ -1,29 +1,35 @@
1
+ from pathlib import Path
2
+
1
3
  import numpy as np
2
- from numpy import array_equal, allclose
3
- import pytest
4
+ from numpy import allclose, array_equal
4
5
 
5
6
  from pyogrio import (
6
- __gdal_version__,
7
7
  __gdal_geos_version__,
8
+ __gdal_version__,
9
+ detect_write_driver,
10
+ get_gdal_config_option,
11
+ get_gdal_data_path,
8
12
  list_drivers,
9
13
  list_layers,
10
14
  read_bounds,
11
15
  read_info,
12
16
  set_gdal_config_options,
13
- get_gdal_config_option,
14
- get_gdal_data_path,
17
+ vsi_listtree,
18
+ vsi_rmtree,
19
+ vsi_unlink,
15
20
  )
16
- from pyogrio.core import detect_write_driver
17
21
  from pyogrio._compat import GDAL_GE_38
18
- from pyogrio.errors import DataSourceError, DataLayerError
19
- from pyogrio.tests.conftest import HAS_SHAPELY, prepare_testfile
20
-
21
22
  from pyogrio._env import GDALEnv
23
+ from pyogrio.errors import DataLayerError, DataSourceError
24
+ from pyogrio.raw import read, write
25
+ from pyogrio.tests.conftest import START_FID, prepare_testfile, requires_shapely
26
+
27
+ import pytest
22
28
 
23
29
  with GDALEnv():
24
30
  # NOTE: this must be AFTER above imports, which init the GDAL and PROJ data
25
31
  # search paths
26
- from pyogrio._ogr import ogr_driver_supports_write, has_gdal_data, has_proj_data
32
+ from pyogrio._ogr import has_gdal_data, has_proj_data, ogr_driver_supports_write
27
33
 
28
34
 
29
35
  try:
@@ -100,9 +106,9 @@ def test_detect_write_driver_unsupported(path):
100
106
  detect_write_driver(path)
101
107
 
102
108
 
103
- @pytest.mark.parametrize("path", ["test.xml", "test.txt"])
109
+ @pytest.mark.parametrize("path", ["test.xml"])
104
110
  def test_detect_write_driver_multiple_unsupported(path):
105
- with pytest.raises(ValueError, match="multiple drivers are available"):
111
+ with pytest.raises(ValueError, match="multiple drivers are available "):
106
112
  detect_write_driver(path)
107
113
 
108
114
 
@@ -151,7 +157,16 @@ def test_list_drivers():
151
157
  assert len(drivers) == len(expected)
152
158
 
153
159
 
154
- def test_list_layers(naturalearth_lowres, naturalearth_lowres_vsi, test_fgdb_vsi):
160
+ def test_list_layers(
161
+ naturalearth_lowres,
162
+ naturalearth_lowres_vsi,
163
+ naturalearth_lowres_vsimem,
164
+ line_zm_file,
165
+ curve_file,
166
+ curve_polygon_file,
167
+ multisurface_file,
168
+ no_geometry_file,
169
+ ):
155
170
  assert array_equal(
156
171
  list_layers(naturalearth_lowres), [["naturalearth_lowres", "Polygon"]]
157
172
  )
@@ -160,21 +175,27 @@ def test_list_layers(naturalearth_lowres, naturalearth_lowres_vsi, test_fgdb_vsi
160
175
  list_layers(naturalearth_lowres_vsi[1]), [["naturalearth_lowres", "Polygon"]]
161
176
  )
162
177
 
178
+ assert array_equal(
179
+ list_layers(naturalearth_lowres_vsimem),
180
+ [["naturalearth_lowres", "MultiPolygon"]],
181
+ )
182
+
163
183
  # Measured 3D is downgraded to plain 3D during read
164
184
  # Make sure this warning is raised
165
185
  with pytest.warns(
166
186
  UserWarning, match=r"Measured \(M\) geometry types are not supported"
167
187
  ):
168
- fgdb_layers = list_layers(test_fgdb_vsi)
169
- # GDAL >= 3.4.0 includes 'another_relationship' layer
170
- assert len(fgdb_layers) >= 7
188
+ assert array_equal(list_layers(line_zm_file), [["line_zm", "LineString Z"]])
171
189
 
172
- # Make sure that nonspatial layer has None for geometry
173
- assert array_equal(fgdb_layers[0], ["basetable_2", None])
190
+ # Curve / surface types are downgraded to plain types
191
+ assert array_equal(list_layers(curve_file), [["curve", "LineString"]])
192
+ assert array_equal(list_layers(curve_polygon_file), [["curvepolygon", "Polygon"]])
193
+ assert array_equal(
194
+ list_layers(multisurface_file), [["multisurface", "MultiPolygon"]]
195
+ )
174
196
 
175
- # Confirm that measured 3D is downgraded to plain 3D during read
176
- assert array_equal(fgdb_layers[3], ["test_lines", "MultiLineString Z"])
177
- assert array_equal(fgdb_layers[6], ["test_areas", "MultiPolygon Z"])
197
+ # Make sure that nonspatial layer has None for geometry
198
+ assert array_equal(list_layers(no_geometry_file), [["no_geometry", None]])
178
199
 
179
200
 
180
201
  def test_list_layers_bytes(geojson_bytes):
@@ -184,6 +205,13 @@ def test_list_layers_bytes(geojson_bytes):
184
205
  assert layers[0, 0] == "test"
185
206
 
186
207
 
208
+ def test_list_layers_nonseekable_bytes(nonseekable_bytes):
209
+ layers = list_layers(nonseekable_bytes)
210
+
211
+ assert layers.shape == (1, 2)
212
+ assert layers[0, 1] == "Point"
213
+
214
+
187
215
  def test_list_layers_filelike(geojson_filelike):
188
216
  layers = list_layers(geojson_filelike)
189
217
 
@@ -191,22 +219,18 @@ def test_list_layers_filelike(geojson_filelike):
191
219
  assert layers[0, 0] == "test"
192
220
 
193
221
 
194
- def test_read_bounds(naturalearth_lowres):
195
- fids, bounds = read_bounds(naturalearth_lowres)
196
- assert fids.shape == (177,)
197
- assert bounds.shape == (4, 177)
198
-
199
- assert fids[0] == 0
200
- # Fiji; wraps antimeridian
201
- assert allclose(bounds[:, 0], [-180.0, -18.28799, 180.0, -16.02088])
202
-
222
+ @pytest.mark.parametrize(
223
+ "testfile",
224
+ ["naturalearth_lowres", "naturalearth_lowres_vsimem", "naturalearth_lowres_vsi"],
225
+ )
226
+ def test_read_bounds(testfile, request):
227
+ path = request.getfixturevalue(testfile)
228
+ path = path if not isinstance(path, tuple) else path[1]
203
229
 
204
- def test_read_bounds_vsi(naturalearth_lowres_vsi):
205
- fids, bounds = read_bounds(naturalearth_lowres_vsi[1])
230
+ fids, bounds = read_bounds(path)
206
231
  assert fids.shape == (177,)
207
232
  assert bounds.shape == (4, 177)
208
-
209
- assert fids[0] == 0
233
+ assert fids[0] == START_FID[Path(path).suffix]
210
234
  # Fiji; wraps antimeridian
211
235
  assert allclose(bounds[:, 0], [-180.0, -18.28799, 180.0, -16.02088])
212
236
 
@@ -218,6 +242,13 @@ def test_read_bounds_bytes(geojson_bytes):
218
242
  assert allclose(bounds[:, 0], [-180.0, -18.28799, 180.0, -16.02088])
219
243
 
220
244
 
245
+ def test_read_bounds_nonseekable_bytes(nonseekable_bytes):
246
+ fids, bounds = read_bounds(nonseekable_bytes)
247
+ assert fids.shape == (1,)
248
+ assert bounds.shape == (4, 1)
249
+ assert allclose(bounds[:, 0], [1, 1, 1, 1])
250
+
251
+
221
252
  def test_read_bounds_filelike(geojson_filelike):
222
253
  fids, bounds = read_bounds(geojson_filelike)
223
254
  assert fids.shape == (3,)
@@ -255,8 +286,12 @@ def test_read_bounds_negative_skip_features(naturalearth_lowres):
255
286
 
256
287
 
257
288
  def test_read_bounds_where_invalid(naturalearth_lowres_all_ext):
258
- with pytest.raises(ValueError, match="Invalid SQL"):
259
- read_bounds(naturalearth_lowres_all_ext, where="invalid")
289
+ if naturalearth_lowres_all_ext.suffix == ".gpkg" and __gdal_version__ >= (3, 11, 0):
290
+ with pytest.raises(DataLayerError, match="no such column"):
291
+ read_bounds(naturalearth_lowres_all_ext, where="invalid")
292
+ else:
293
+ with pytest.raises(ValueError, match="Invalid SQL"):
294
+ read_bounds(naturalearth_lowres_all_ext, where="invalid")
260
295
 
261
296
 
262
297
  def test_read_bounds_where(naturalearth_lowres):
@@ -285,12 +320,9 @@ def test_read_bounds_bbox(naturalearth_lowres_all_ext):
285
320
  fids, bounds = read_bounds(naturalearth_lowres_all_ext, bbox=(-85, 8, -80, 10))
286
321
 
287
322
  assert fids.shape == (2,)
288
- if naturalearth_lowres_all_ext.suffix == ".gpkg":
289
- # fid in gpkg is 1-based
290
- assert array_equal(fids, [34, 35]) # PAN, CRI
291
- else:
292
- # fid in other formats is 0-based
293
- assert array_equal(fids, [33, 34]) # PAN, CRI
323
+ fids_expected = np.array([33, 34]) # PAN, CRI
324
+ fids_expected += START_FID[naturalearth_lowres_all_ext.suffix]
325
+ assert array_equal(fids, fids_expected)
294
326
 
295
327
  assert bounds.shape == (4, 2)
296
328
  assert allclose(
@@ -302,9 +334,7 @@ def test_read_bounds_bbox(naturalearth_lowres_all_ext):
302
334
  )
303
335
 
304
336
 
305
- @pytest.mark.skipif(
306
- not HAS_SHAPELY, reason="Shapely is required for mask functionality"
307
- )
337
+ @requires_shapely
308
338
  @pytest.mark.parametrize(
309
339
  "mask",
310
340
  [
@@ -318,9 +348,7 @@ def test_read_bounds_mask_invalid(naturalearth_lowres, mask):
318
348
  read_bounds(naturalearth_lowres, mask=mask)
319
349
 
320
350
 
321
- @pytest.mark.skipif(
322
- not HAS_SHAPELY, reason="Shapely is required for mask functionality"
323
- )
351
+ @requires_shapely
324
352
  def test_read_bounds_bbox_mask_invalid(naturalearth_lowres):
325
353
  with pytest.raises(ValueError, match="cannot set both 'bbox' and 'mask'"):
326
354
  read_bounds(
@@ -328,9 +356,7 @@ def test_read_bounds_bbox_mask_invalid(naturalearth_lowres):
328
356
  )
329
357
 
330
358
 
331
- @pytest.mark.skipif(
332
- not HAS_SHAPELY, reason="Shapely is required for mask functionality"
333
- )
359
+ @requires_shapely
334
360
  @pytest.mark.parametrize(
335
361
  "mask,expected",
336
362
  [
@@ -361,12 +387,8 @@ def test_read_bounds_mask(naturalearth_lowres_all_ext, mask, expected):
361
387
 
362
388
  fids = read_bounds(naturalearth_lowres_all_ext, mask=mask)[0]
363
389
 
364
- if naturalearth_lowres_all_ext.suffix == ".gpkg":
365
- # fid in gpkg is 1-based
366
- assert array_equal(fids, np.array(expected) + 1)
367
- else:
368
- # fid in other formats is 0-based
369
- assert array_equal(fids, expected)
390
+ fids_expected = np.array(expected) + START_FID[naturalearth_lowres_all_ext.suffix]
391
+ assert array_equal(fids, fids_expected)
370
392
 
371
393
 
372
394
  @pytest.mark.skipif(
@@ -382,21 +404,15 @@ def test_read_bounds_bbox_intersects_vs_envelope_overlaps(naturalearth_lowres_al
382
404
  if __gdal_geos_version__ is None:
383
405
  # bboxes for CAN, RUS overlap but do not intersect geometries
384
406
  assert fids.shape == (4,)
385
- if naturalearth_lowres_all_ext.suffix == ".gpkg":
386
- # fid in gpkg is 1-based
387
- assert array_equal(fids, [4, 5, 19, 28]) # CAN, USA, RUS, MEX
388
- else:
389
- # fid in other formats is 0-based
390
- assert array_equal(fids, [3, 4, 18, 27]) # CAN, USA, RUS, MEX
407
+ fids_expected = np.array([3, 4, 18, 27]) # CAN, USA, RUS, MEX
408
+ fids_expected += START_FID[naturalearth_lowres_all_ext.suffix]
409
+ assert array_equal(fids, fids_expected)
391
410
 
392
411
  else:
393
412
  assert fids.shape == (2,)
394
- if naturalearth_lowres_all_ext.suffix == ".gpkg":
395
- # fid in gpkg is 1-based
396
- assert array_equal(fids, [5, 28]) # USA, MEX
397
- else:
398
- # fid in other formats is 0-based
399
- assert array_equal(fids, [4, 27]) # USA, MEX
413
+ fids_expected = np.array([4, 27]) # USA, MEX
414
+ fids_expected += START_FID[naturalearth_lowres_all_ext.suffix]
415
+ assert array_equal(fids, fids_expected)
400
416
 
401
417
 
402
418
  @pytest.mark.parametrize("naturalearth_lowres", [".shp", ".gpkg"], indirect=True)
@@ -426,7 +442,8 @@ def test_read_info(naturalearth_lowres):
426
442
  elif naturalearth_lowres.suffix == ".shp":
427
443
  # fid_column == "" for formats where fid is not physically stored
428
444
  assert meta["fid_column"] == ""
429
- # geometry_name == "" for formats where geometry column name cannot be customized
445
+ # geometry_name == "" for formats where geometry column name cannot be
446
+ # customized
430
447
  assert meta["geometry_name"] == ""
431
448
  assert meta["geometry_type"] == "Polygon"
432
449
  assert meta["driver"] == "ESRI Shapefile"
@@ -435,8 +452,14 @@ def test_read_info(naturalearth_lowres):
435
452
  raise ValueError(f"test not implemented for ext {naturalearth_lowres.suffix}")
436
453
 
437
454
 
438
- def test_read_info_vsi(naturalearth_lowres_vsi):
439
- meta = read_info(naturalearth_lowres_vsi[1])
455
+ @pytest.mark.parametrize(
456
+ "testfile", ["naturalearth_lowres_vsimem", "naturalearth_lowres_vsi"]
457
+ )
458
+ def test_read_info_vsi(testfile, request):
459
+ path = request.getfixturevalue(testfile)
460
+ path = path if not isinstance(path, tuple) else path[1]
461
+
462
+ meta = read_info(path)
440
463
 
441
464
  assert meta["fields"].shape == (5,)
442
465
  assert meta["features"] == 177
@@ -449,6 +472,13 @@ def test_read_info_bytes(geojson_bytes):
449
472
  assert meta["features"] == 3
450
473
 
451
474
 
475
+ def test_read_info_nonseekable_bytes(nonseekable_bytes):
476
+ meta = read_info(nonseekable_bytes)
477
+
478
+ assert meta["fields"].shape == (0,)
479
+ assert meta["features"] == 1
480
+
481
+
452
482
  def test_read_info_filelike(geojson_filelike):
453
483
  meta = read_info(geojson_filelike)
454
484
 
@@ -483,8 +513,8 @@ def test_read_info_filelike(geojson_filelike):
483
513
  ),
484
514
  ],
485
515
  )
486
- def test_read_info_dataset_kwargs(data_dir, dataset_kwargs, fields):
487
- meta = read_info(data_dir / "test_nested.geojson", **dataset_kwargs)
516
+ def test_read_info_dataset_kwargs(nested_geojson_file, dataset_kwargs, fields):
517
+ meta = read_info(nested_geojson_file, **dataset_kwargs)
488
518
  assert meta["fields"].tolist() == fields
489
519
 
490
520
 
@@ -543,8 +573,8 @@ def test_read_info_unspecified_layer_warning(data_dir):
543
573
  read_info(data_dir / "sample.osm.pbf")
544
574
 
545
575
 
546
- def test_read_info_without_geometry(test_fgdb_vsi):
547
- assert read_info(test_fgdb_vsi, layer="basetable_2")["total_bounds"] is None
576
+ def test_read_info_without_geometry(no_geometry_file):
577
+ assert read_info(no_geometry_file)["total_bounds"] is None
548
578
 
549
579
 
550
580
  @pytest.mark.parametrize(
@@ -586,3 +616,67 @@ def test_error_handling_warning(capfd, naturalearth_lowres):
586
616
  read_info(naturalearth_lowres, INVALID="YES")
587
617
 
588
618
  assert capfd.readouterr().err == ""
619
+
620
+
621
+ def test_vsimem_listtree_rmtree_unlink(naturalearth_lowres):
622
+ """Test all basic functionalities of file handling in /vsimem/."""
623
+ # Prepare test data in /vsimem
624
+ meta, _, geometry, field_data = read(naturalearth_lowres)
625
+ meta["spatial_index"] = False
626
+ meta["geometry_type"] = "MultiPolygon"
627
+ test_file_path = Path("/vsimem/pyogrio_test_naturalearth_lowres.gpkg")
628
+ test_dir_path = Path(f"/vsimem/pyogrio_dir_test/{naturalearth_lowres.stem}.gpkg")
629
+
630
+ write(test_file_path, geometry, field_data, **meta)
631
+ write(test_dir_path, geometry, field_data, **meta)
632
+
633
+ # Check if everything was created properly with listtree
634
+ files = vsi_listtree("/vsimem/")
635
+ assert test_file_path.as_posix() in files
636
+ assert test_dir_path.as_posix() in files
637
+
638
+ # Check listtree with pattern
639
+ files = vsi_listtree("/vsimem/", pattern="pyogrio_dir_test*.gpkg")
640
+ assert test_file_path.as_posix() not in files
641
+ assert test_dir_path.as_posix() in files
642
+
643
+ files = vsi_listtree("/vsimem/", pattern="pyogrio_test*.gpkg")
644
+ assert test_file_path.as_posix() in files
645
+ assert test_dir_path.as_posix() not in files
646
+
647
+ # Remove test_dir and its contents
648
+ vsi_rmtree(test_dir_path.parent)
649
+ files = vsi_listtree("/vsimem/")
650
+ assert test_file_path.as_posix() in files
651
+ assert test_dir_path.as_posix() not in files
652
+
653
+ # Remove test_file
654
+ vsi_unlink(test_file_path)
655
+
656
+
657
+ def test_vsimem_rmtree_error(naturalearth_lowres_vsimem):
658
+ with pytest.raises(NotADirectoryError, match="Path is not a directory"):
659
+ vsi_rmtree(naturalearth_lowres_vsimem)
660
+
661
+ with pytest.raises(FileNotFoundError, match="Path does not exist"):
662
+ vsi_rmtree("/vsimem/non-existent")
663
+
664
+ with pytest.raises(
665
+ OSError, match="path to in-memory file or directory is required"
666
+ ):
667
+ vsi_rmtree("/vsimem")
668
+ with pytest.raises(
669
+ OSError, match="path to in-memory file or directory is required"
670
+ ):
671
+ vsi_rmtree("/vsimem/")
672
+
673
+ # Verify that naturalearth_lowres_vsimem still exists.
674
+ assert naturalearth_lowres_vsimem.as_posix() in vsi_listtree("/vsimem")
675
+
676
+
677
+ def test_vsimem_unlink_error(naturalearth_lowres_vsimem):
678
+ with pytest.raises(IsADirectoryError, match="Path is a directory"):
679
+ vsi_unlink(naturalearth_lowres_vsimem.parent)
680
+
681
+ with pytest.raises(FileNotFoundError, match="Path does not exist"):
682
+ vsi_unlink("/vsimem/non-existent.gpkg")