vecorel-cli 0.2.19__tar.gz → 0.2.20__tar.gz

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.
Files changed (83) hide show
  1. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/PKG-INFO +1 -1
  2. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/pyproject.toml +1 -1
  3. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_convert.py +50 -0
  4. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/conversion/base.py +22 -5
  5. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/conversion/duckdb.py +1 -1
  6. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli.egg-info/PKG-INFO +1 -1
  7. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/LICENSE +0 -0
  8. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/README.md +0 -0
  9. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/setup.cfg +0 -0
  10. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_convert_duckdb.py +0 -0
  11. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_converters.py +0 -0
  12. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_create_geojson.py +0 -0
  13. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_create_geoparquet.py +0 -0
  14. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_create_stac.py +0 -0
  15. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_describe.py +0 -0
  16. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_download.py +0 -0
  17. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_encoding_auto.py +0 -0
  18. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_encoding_geojson.py +0 -0
  19. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_encoding_geoparquet.py +0 -0
  20. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_hilbert.py +0 -0
  21. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_improve.py +0 -0
  22. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_jsonschema.py +0 -0
  23. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_merge.py +0 -0
  24. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_ops.py +0 -0
  25. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_rename_extension.py +0 -0
  26. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_validate.py +0 -0
  27. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/tests/test_validate_schema.py +0 -0
  28. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/__init__.py +0 -0
  29. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/basecommand.py +0 -0
  30. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/cli/__init__.py +0 -0
  31. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/cli/logger.py +0 -0
  32. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/cli/options.py +0 -0
  33. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/cli/path_url.py +0 -0
  34. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/cli/setup.py +0 -0
  35. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/cli/util.py +0 -0
  36. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/const.py +0 -0
  37. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/conversion/__init__.py +0 -0
  38. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/conversion/admin.py +0 -0
  39. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/conversion/flatdict.py +0 -0
  40. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/convert.py +0 -0
  41. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/converters.py +0 -0
  42. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/create_geojson.py +0 -0
  43. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/create_geoparquet.py +0 -0
  44. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/create_jsonschema.py +0 -0
  45. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/create_stac.py +0 -0
  46. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/datasets/__init__.py +0 -0
  47. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/datasets/template.py +0 -0
  48. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/describe.py +0 -0
  49. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/encoding/__init__.py +0 -0
  50. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/encoding/auto.py +0 -0
  51. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/encoding/base.py +0 -0
  52. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/encoding/geojson.py +0 -0
  53. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/encoding/geoparquet.py +0 -0
  54. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/improve.py +0 -0
  55. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/jsonschema/__init__.py +0 -0
  56. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/jsonschema/template.py +0 -0
  57. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/merge.py +0 -0
  58. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/parquet/__init__.py +0 -0
  59. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/parquet/geopandas.py +0 -0
  60. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/parquet/types.py +0 -0
  61. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/registry.py +0 -0
  62. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/rename_extension.py +0 -0
  63. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/validate.py +0 -0
  64. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/validate_schema.py +0 -0
  65. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/validation/__init__.py +0 -0
  66. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/validation/base.py +0 -0
  67. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/validation/data.py +0 -0
  68. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/validation/geojson.py +0 -0
  69. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/validation/geoparquet.py +0 -0
  70. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/vecorel/__init__.py +0 -0
  71. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/vecorel/collection.py +0 -0
  72. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/vecorel/extensions.py +0 -0
  73. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/vecorel/hilbert.py +0 -0
  74. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/vecorel/ops.py +0 -0
  75. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/vecorel/schemas.py +0 -0
  76. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/vecorel/typing.py +0 -0
  77. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/vecorel/util.py +0 -0
  78. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli/vecorel/version.py +0 -0
  79. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli.egg-info/SOURCES.txt +0 -0
  80. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli.egg-info/dependency_links.txt +0 -0
  81. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli.egg-info/entry_points.txt +0 -0
  82. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli.egg-info/requires.txt +0 -0
  83. {vecorel_cli-0.2.19 → vecorel_cli-0.2.20}/vecorel_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vecorel-cli
3
- Version: 0.2.19
3
+ Version: 0.2.20
4
4
  Summary: CLI tools such as validation and file format conversion for vecorel.
5
5
  Author: Matthias Mohr
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "vecorel-cli"
7
- version = "0.2.19"
7
+ version = "0.2.20"
8
8
  description = "CLI tools such as validation and file format conversion for vecorel."
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -199,3 +199,53 @@ def test_converter_can_keep_the_constants_in_columns(tmp_folder, monkeypatch, ch
199
199
  for key in ("admin:country_code", "admin:subdivision_code", "determination_datetime"):
200
200
  assert key in schema.names, f"{key} should have stayed a column"
201
201
  assert key not in collection, f"{key} should not be in the collection metadata"
202
+
203
+
204
+ def test_default_variant_is_chosen_before_get_urls():
205
+ """A converter that overrides get_urls() must see the default variant, so the
206
+ default lives in convert() and not in the base get_urls() it replaces."""
207
+
208
+ class Converter(BaseConverter):
209
+ id = "variants"
210
+ # oldest first: the latest year is still the default
211
+ variants = {
212
+ "2024": "https://example.com/2024.gpkg",
213
+ "2025": "https://example.com/2025.gpkg",
214
+ }
215
+
216
+ def get_urls(self):
217
+ # like the converters that look their files up by year
218
+ return {f"https://example.com/{self.variant}/": f"{self.variant}.gpkg"}
219
+
220
+ converter = Converter()
221
+ converter.select_variant(None)
222
+ assert converter.variant == "2025"
223
+ assert converter.get_urls() == {"https://example.com/2025/": "2025.gpkg"}
224
+
225
+ converter.select_variant("2024")
226
+ assert converter.variant == "2024"
227
+ assert converter.get_urls() == {"https://example.com/2024/": "2024.gpkg"}
228
+
229
+
230
+ def test_default_variant_is_the_first_declared_unless_the_variants_are_years():
231
+ class Converter(BaseConverter):
232
+ id = "variants"
233
+ variants = {"full": "https://example.com/full.gpkg", "2025": "https://example.com/2025"}
234
+
235
+ converter = Converter()
236
+ converter.select_variant(None)
237
+ assert converter.variant == "full"
238
+
239
+
240
+ def test_get_urls_rejects_an_unknown_variant():
241
+ class Converter(BaseConverter):
242
+ id = "variants"
243
+ variants = {"2025": "https://example.com/2025.gpkg"}
244
+
245
+ converter = Converter()
246
+ converter.select_variant("2025")
247
+ assert converter.get_urls() == "https://example.com/2025.gpkg"
248
+
249
+ converter.select_variant("1999")
250
+ with pytest.raises(ValueError, match="Unknown variant '1999'"):
251
+ converter.get_urls()
@@ -4,6 +4,7 @@ import hashlib
4
4
  import inspect
5
5
  import json
6
6
  import os
7
+ import re
7
8
  import sys
8
9
  import tarfile
9
10
  import zipfile
@@ -92,6 +93,24 @@ class BaseConverter(LoggerMixin):
92
93
  "variants = {} when the inherited ones do not apply."
93
94
  )
94
95
 
96
+ def select_variant(self, variant: Optional[str]) -> None:
97
+ """Store the requested variant; without one, the default variant is used.
98
+ Done at the start of convert() rather than in get_urls(), so a converter that
99
+ overrides get_urls() does not have to repeat the default, and so the default is
100
+ also set when the user supplies the input files."""
101
+ self.variant = variant
102
+ if self.variants and self.variant is None:
103
+ self.variant = self.default_variant()
104
+ opts = ", ".join(self.variants)
105
+ self.warning(f"No variant given, choosing {self.variant} from {opts}")
106
+
107
+ def default_variant(self) -> str:
108
+ """The latest year when the variants are years, otherwise the first declared."""
109
+ keys = list(self.variants)
110
+ if all(re.fullmatch(r"\d{4}", key) for key in keys):
111
+ return max(keys)
112
+ return keys[0]
113
+
95
114
  def _check_id_mapping(self):
96
115
  """Warn before converting when nothing is mapped to the required `id` property.
97
116
  Unmapped columns are dropped, which also removes the column filled by
@@ -344,13 +363,11 @@ class BaseConverter(LoggerMixin):
344
363
  def get_urls(self):
345
364
  urls = self.sources
346
365
  if not urls and self.variants:
347
- opts = ", ".join(list(self.variants.keys()))
348
- if self.variant is None:
349
- self.variant = next(iter(self.variants))
350
- self.warning(f"Choosing first available variant {self.variant} from {opts}")
366
+ # the default variant is chosen in convert(), see select_variant()
351
367
  if self.variant in self.variants:
352
368
  urls = self.variants[self.variant]
353
369
  else:
370
+ opts = ", ".join(self.variants)
354
371
  raise ValueError(f"Unknown variant '{self.variant}', choose from {opts}")
355
372
  return urls
356
373
 
@@ -483,7 +500,7 @@ class BaseConverter(LoggerMixin):
483
500
  original_geometries=False,
484
501
  **kwargs,
485
502
  ) -> str:
486
- self.variant = variant
503
+ self.select_variant(variant)
487
504
  cid = self.id.strip()
488
505
  if self.bbox is not None and len(self.bbox) != 4:
489
506
  raise ValueError("If provided, the bounding box must consist of 4 numbers")
@@ -74,7 +74,7 @@ class DuckDBBaseConverter(BaseConverter):
74
74
  original_geometries=False,
75
75
  **kwargs,
76
76
  ) -> str:
77
- self.variant = variant
77
+ self.select_variant(variant)
78
78
  cid = self.id.strip()
79
79
  if self.bbox is not None and len(self.bbox) != 4:
80
80
  raise ValueError("If provided, the bounding box must consist of 4 numbers")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vecorel-cli
3
- Version: 0.2.19
3
+ Version: 0.2.20
4
4
  Summary: CLI tools such as validation and file format conversion for vecorel.
5
5
  Author: Matthias Mohr
6
6
  License-Expression: Apache-2.0
File without changes
File without changes
File without changes