vecorel-cli 0.2.2__tar.gz → 0.2.3__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 (77) hide show
  1. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/PKG-INFO +1 -1
  2. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/pyproject.toml +1 -1
  3. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/vecorel/schemas.py +107 -13
  4. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli.egg-info/PKG-INFO +1 -1
  5. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/LICENSE +0 -0
  6. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/README.md +0 -0
  7. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/setup.cfg +0 -0
  8. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/tests/test_convert.py +0 -0
  9. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/tests/test_converters.py +0 -0
  10. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/tests/test_create_geojson.py +0 -0
  11. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/tests/test_create_geoparquet.py +0 -0
  12. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/tests/test_create_stac.py +0 -0
  13. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/tests/test_describe.py +0 -0
  14. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/tests/test_encoding_auto.py +0 -0
  15. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/tests/test_encoding_geojson.py +0 -0
  16. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/tests/test_encoding_geoparquet.py +0 -0
  17. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/tests/test_improve.py +0 -0
  18. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/tests/test_jsonschema.py +0 -0
  19. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/tests/test_merge.py +0 -0
  20. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/tests/test_ops.py +0 -0
  21. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/tests/test_rename_extension.py +0 -0
  22. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/tests/test_validate.py +0 -0
  23. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/tests/test_validate_schema.py +0 -0
  24. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/__init__.py +0 -0
  25. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/basecommand.py +0 -0
  26. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/cli/__init__.py +0 -0
  27. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/cli/logger.py +0 -0
  28. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/cli/options.py +0 -0
  29. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/cli/path_url.py +0 -0
  30. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/cli/setup.py +0 -0
  31. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/cli/util.py +0 -0
  32. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/const.py +0 -0
  33. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/conversion/__init__.py +0 -0
  34. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/conversion/admin.py +0 -0
  35. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/conversion/base.py +0 -0
  36. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/convert.py +0 -0
  37. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/converters.py +0 -0
  38. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/create_geojson.py +0 -0
  39. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/create_geoparquet.py +0 -0
  40. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/create_jsonschema.py +0 -0
  41. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/create_stac.py +0 -0
  42. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/datasets/__init__.py +0 -0
  43. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/datasets/template.py +0 -0
  44. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/describe.py +0 -0
  45. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/encoding/__init__.py +0 -0
  46. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/encoding/auto.py +0 -0
  47. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/encoding/base.py +0 -0
  48. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/encoding/geojson.py +0 -0
  49. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/encoding/geoparquet.py +0 -0
  50. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/improve.py +0 -0
  51. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/jsonschema/__init__.py +0 -0
  52. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/jsonschema/template.py +0 -0
  53. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/merge.py +0 -0
  54. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/parquet/__init__.py +0 -0
  55. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/parquet/geopandas.py +0 -0
  56. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/parquet/types.py +0 -0
  57. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/registry.py +0 -0
  58. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/rename_extension.py +0 -0
  59. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/validate.py +0 -0
  60. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/validate_schema.py +0 -0
  61. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/validation/__init__.py +0 -0
  62. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/validation/base.py +0 -0
  63. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/validation/data.py +0 -0
  64. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/validation/geojson.py +0 -0
  65. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/validation/geoparquet.py +0 -0
  66. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/vecorel/__init__.py +0 -0
  67. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/vecorel/collection.py +0 -0
  68. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/vecorel/extensions.py +0 -0
  69. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/vecorel/ops.py +0 -0
  70. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/vecorel/typing.py +0 -0
  71. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/vecorel/util.py +0 -0
  72. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli/vecorel/version.py +0 -0
  73. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli.egg-info/SOURCES.txt +0 -0
  74. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli.egg-info/dependency_links.txt +0 -0
  75. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli.egg-info/entry_points.txt +0 -0
  76. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/vecorel_cli.egg-info/requires.txt +0 -0
  77. {vecorel_cli-0.2.2 → vecorel_cli-0.2.3}/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.2
3
+ Version: 0.2.3
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.2"
7
+ version = "0.2.3"
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"
@@ -95,13 +95,105 @@ class VecorelSchema(dict):
95
95
  if self.get_sdl_version() != other.get_sdl_version():
96
96
  raise ValueError("Schemas have different SDL versions, can't merge.")
97
97
 
98
- self._check_conflicts(other, "required")
99
- self._check_conflicts(other, "collection")
100
- self._check_conflicts(other, "properties")
98
+ # Merge required properties
99
+ self["required"] = list(set(self["required"]) | set(other.get("required", [])))
100
+
101
+ # Merge collection details
102
+ other_collection = other.get("collection", {}).items()
103
+ for key, value in other_collection:
104
+ if key not in self["collection"]:
105
+ self["collection"][key] = value
106
+ else:
107
+ self_value = self["collection"][key]
108
+ if self_value != value:
109
+ raise ValueError(
110
+ f"Schema has conflicts in 'collection': Property '{key}' has values '{self_value}' and '{value}'."
111
+ )
112
+ else:
113
+ pass # exists as is, no action needed
114
+
115
+ # Merge actual schemas for properties
116
+ self["properties"] = self._merge_properties(
117
+ self["properties"], other.get("properties", {}), "properties"
118
+ )
101
119
 
102
- self["required"] += other.get("required", [])
103
- self["collection"].update(other.get("collection", {}))
104
- self["properties"].update(other.get("properties", {}))
120
+ def _merge_properties(self, a: dict, b: dict, path: str = "") -> dict:
121
+ all_properties = set(a.keys()) | set(b.keys())
122
+ a = a.copy()
123
+ for key in all_properties:
124
+ if key in a:
125
+ if key in b:
126
+ # merge schemas
127
+ a[key] = self._merge_json_schema(a[key], b[key], f"{path}.{key}")
128
+ else:
129
+ pass # doesn't exist in other schema, keep as is
130
+ else:
131
+ # doesn't exist in this schema, just add it from the other schema
132
+ a[key] = b[key]
133
+ return a
134
+
135
+ def _merge_json_schema(self, a: dict, b: dict, path: str = "") -> dict:
136
+ """Merge two JSON schemas"""
137
+ if not isinstance(a, dict) or not isinstance(b, dict):
138
+ raise ValueError(
139
+ f"Conflict in '{path}': Cannot merge types '{type(a)}' and '{type(b)}'."
140
+ )
141
+
142
+ a = a.copy()
143
+ all_keys = set(a.keys()) | set(b.keys())
144
+ for key in all_keys:
145
+ if key == "additionalProperties":
146
+ # We need to handle additionalProperties separately as it has a default value
147
+ ap1 = a.get("additionalProperties", False)
148
+ ap2 = b.get("additionalProperties", False)
149
+ if isinstance(ap1, dict) and isinstance(ap2, dict):
150
+ a[key] = self._merge_json_schema(ap1, ap2, f"{path}.additionalProperties")
151
+ elif a[key] is False or b[key] is False:
152
+ a[key] = False
153
+ elif a[key] is True and isinstance(b[key], dict):
154
+ a[key] = b[key]
155
+ else:
156
+ pass # a is good as is, no action needed
157
+ elif key not in b:
158
+ continue
159
+ elif key not in a:
160
+ a[key] = b[key]
161
+ else:
162
+ p = f"{path}.{key}"
163
+ match key:
164
+ case "$schema":
165
+ pass # ignore for now. todo: Properly check versions
166
+ case "required":
167
+ a[key] = list(set(a[key]) | set(b[key]))
168
+ case ("enum", "geometryTypes"):
169
+ a[key] = list(set(a[key]) & set(b[key]))
170
+ case ("items", "contains"):
171
+ a[key] = self._merge_json_schema(a[key], b[key], p)
172
+ case ("properties", "patternProperties"):
173
+ a[key] = self._merge_properties(a[key], b[key], p)
174
+ case ("minLength", "minimum", "exclusiveMinimum", "minItems", "minProperties"):
175
+ a[key] = max(a[key], b[key])
176
+ case ("maxLength", "maximum", "exclusiveMaximum", "maxItems", "maxProperties"):
177
+ a[key] = min(a[key], b[key])
178
+ case ("deprecated", "uniqueItems"):
179
+ if b[key]:
180
+ a[key] = True
181
+ case _: # description, type, format, pattern, default
182
+ if a[key] == b[key]:
183
+ a[key] = b[key]
184
+ else:
185
+ raise ValueError(f"Conflict in '{p}': '{a[key]}' != '{b[key]}'")
186
+
187
+ if "minimum" in a and "exclusiveMinimum" in a:
188
+ raise ValueError(
189
+ f"Conflict in '{path}': 'minimum' and 'exclusiveMinimum' cannot coexist"
190
+ )
191
+ if "maximum" in a and "exclusiveMaximum" in a:
192
+ raise ValueError(
193
+ f"Conflict in '{path}': 'maximum' and 'exclusiveMaximum' cannot coexist"
194
+ )
195
+
196
+ return a
105
197
 
106
198
  def _check_conflicts(self, other: "VecorelSchema", where: str):
107
199
  """Check if there are conflicts between two sets of properties"""
@@ -109,13 +201,15 @@ class VecorelSchema(dict):
109
201
  b = other.get(where)
110
202
  if a is None or b is None:
111
203
  return
112
- if isinstance(a, dict):
113
- a = a.keys()
114
- if isinstance(b, dict):
115
- b = b.keys()
116
- inter = set(a).intersection(set(b))
117
- if len(inter) > 0:
118
- raise ValueError(f"Schema has a conflict: {inter} in '{where}'.")
204
+ if isinstance(a, dict) and isinstance(b, dict):
205
+ k1 = a.keys()
206
+ k2 = b.keys()
207
+ intersection = set(k1).intersection(set(k2))
208
+ for key in intersection:
209
+ if a[key] != b[key]:
210
+ raise ValueError(
211
+ f"Schema has conflicts: {', '.join(intersection)} in '{where}', e.g. for '{key}' values are '{a[key]}' and '{b[key]}'."
212
+ )
119
213
 
120
214
  def pick(self, property_names: list[str], rename: dict[str, str] = {}) -> "VecorelSchema":
121
215
  """Pick and rename schemas for specific properties"""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vecorel-cli
3
- Version: 0.2.2
3
+ Version: 0.2.3
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