vecorel-cli 0.2.16__tar.gz → 0.2.17__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.
- {vecorel_cli-0.2.16/vecorel_cli.egg-info → vecorel_cli-0.2.17}/PKG-INFO +1 -1
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/pyproject.toml +1 -1
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/tests/test_convert.py +21 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/tests/test_encoding_geojson.py +23 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/conversion/base.py +4 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/encoding/geojson.py +8 -3
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17/vecorel_cli.egg-info}/PKG-INFO +1 -1
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/LICENSE +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/README.md +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/setup.cfg +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/tests/test_converters.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/tests/test_create_geojson.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/tests/test_create_geoparquet.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/tests/test_create_stac.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/tests/test_describe.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/tests/test_encoding_auto.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/tests/test_encoding_geoparquet.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/tests/test_improve.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/tests/test_jsonschema.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/tests/test_merge.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/tests/test_ops.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/tests/test_rename_extension.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/tests/test_validate.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/tests/test_validate_schema.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/__init__.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/basecommand.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/cli/__init__.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/cli/logger.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/cli/options.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/cli/path_url.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/cli/setup.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/cli/util.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/const.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/conversion/__init__.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/conversion/admin.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/conversion/flatdict.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/convert.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/converters.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/create_geojson.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/create_geoparquet.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/create_jsonschema.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/create_stac.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/datasets/__init__.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/datasets/template.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/describe.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/encoding/__init__.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/encoding/auto.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/encoding/base.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/encoding/geoparquet.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/improve.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/jsonschema/__init__.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/jsonschema/template.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/merge.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/parquet/__init__.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/parquet/geopandas.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/parquet/types.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/registry.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/rename_extension.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/validate.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/validate_schema.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/validation/__init__.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/validation/base.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/validation/data.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/validation/geojson.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/validation/geoparquet.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/vecorel/__init__.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/vecorel/collection.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/vecorel/extensions.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/vecorel/hilbert.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/vecorel/ops.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/vecorel/schemas.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/vecorel/typing.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/vecorel/util.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli/vecorel/version.py +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli.egg-info/SOURCES.txt +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli.egg-info/dependency_links.txt +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli.egg-info/entry_points.txt +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli.egg-info/requires.txt +0 -0
- {vecorel_cli-0.2.16 → vecorel_cli-0.2.17}/vecorel_cli.egg-info/top_level.txt +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import sys
|
|
2
3
|
from pathlib import Path
|
|
3
4
|
|
|
@@ -146,6 +147,26 @@ def test_template_from_package_folder():
|
|
|
146
147
|
assert isinstance(converter, ConvertData), "Should succeed and not throw an exception"
|
|
147
148
|
|
|
148
149
|
|
|
150
|
+
@pytest.mark.parametrize("bom", [False, True], ids=["without-bom", "with-bom"])
|
|
151
|
+
def test_read_geojson_decodes_utf8(tmp_folder, cp1252_locale, bom):
|
|
152
|
+
file_path = tmp_folder / "umlaut.json"
|
|
153
|
+
feature = {
|
|
154
|
+
"type": "Feature",
|
|
155
|
+
"id": "1",
|
|
156
|
+
"properties": {"name": "Grünland"},
|
|
157
|
+
"geometry": {"type": "Point", "coordinates": [0, 0]},
|
|
158
|
+
}
|
|
159
|
+
file_path.write_text(
|
|
160
|
+
# ensure_ascii=False so the file really holds multi-byte UTF-8, not an escape sequence
|
|
161
|
+
json.dumps({"type": "FeatureCollection", "features": [feature]}, ensure_ascii=False),
|
|
162
|
+
encoding="utf-8-sig" if bom else "utf-8",
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
gdf = BaseConverter().read_geojson(str(file_path))
|
|
166
|
+
|
|
167
|
+
assert gdf["name"].iloc[0] == "Grünland"
|
|
168
|
+
|
|
169
|
+
|
|
149
170
|
def test_data_access_exception(capsys, tmp_folder):
|
|
150
171
|
# todo: use fixture
|
|
151
172
|
logger.remove()
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import json
|
|
1
2
|
from pathlib import Path
|
|
2
3
|
|
|
3
4
|
import pytest
|
|
@@ -55,3 +56,25 @@ def test_get_collection_returns_existing(tmp_folder):
|
|
|
55
56
|
|
|
56
57
|
result = geojson.get_collection()
|
|
57
58
|
assert result == expected
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@pytest.mark.parametrize("bom", [False, True], ids=["without-bom", "with-bom"])
|
|
62
|
+
def test_read_geojson_decodes_utf8(tmp_folder, cp1252_locale, bom):
|
|
63
|
+
feature = {
|
|
64
|
+
"type": "Feature",
|
|
65
|
+
"id": "1",
|
|
66
|
+
"properties": {"name": "Grünland"},
|
|
67
|
+
"geometry": {"type": "Point", "coordinates": [0, 0]},
|
|
68
|
+
}
|
|
69
|
+
file_path = tmp_folder / "umlaut.json"
|
|
70
|
+
file_path.write_text(
|
|
71
|
+
# ensure_ascii=False so the file really holds multi-byte UTF-8, not an escape sequence
|
|
72
|
+
json.dumps({"type": "FeatureCollection", "features": [feature]}, ensure_ascii=False),
|
|
73
|
+
encoding="utf-8-sig" if bom else "utf-8",
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
geojson = GeoJSON(file_path)
|
|
77
|
+
|
|
78
|
+
assert geojson.read_geojson()["features"][0]["properties"]["name"] == "Grünland"
|
|
79
|
+
# read(num=...) takes the streaming branch, which opens the file separately
|
|
80
|
+
assert geojson.read(num=1)["name"].iloc[0] == "Grünland"
|
|
@@ -24,6 +24,7 @@ from geopandas import GeoDataFrame
|
|
|
24
24
|
|
|
25
25
|
from ..cli.logger import LoggerMixin
|
|
26
26
|
from ..cli.util import display_pandas_unrestricted
|
|
27
|
+
from ..encoding.geojson import READ_ENCODING
|
|
27
28
|
from ..encoding.geoparquet import GeoParquet
|
|
28
29
|
from ..vecorel.collection import Collection
|
|
29
30
|
from ..vecorel.hilbert import hilbert_sort_geodataframe
|
|
@@ -218,6 +219,9 @@ class BaseConverter(LoggerMixin):
|
|
|
218
219
|
yield GeoDataFrame(data), path, uri, layer
|
|
219
220
|
|
|
220
221
|
def read_geojson(self, path, **kwargs):
|
|
222
|
+
# open_options is shared with gpd.read_parquet() and gpd.read_file(), so a converter
|
|
223
|
+
# cannot set a default encoding there without breaking the other two readers.
|
|
224
|
+
kwargs.setdefault("encoding", READ_ENCODING)
|
|
221
225
|
with open(path, **kwargs) as f:
|
|
222
226
|
obj = json.load(f)
|
|
223
227
|
|
|
@@ -17,6 +17,11 @@ from ..vecorel.util import load_file, to_iso8601
|
|
|
17
17
|
from ..vecorel.version import vecorel_version
|
|
18
18
|
from .base import BaseEncoding
|
|
19
19
|
|
|
20
|
+
# GeoJSON is UTF-8 (RFC 8259, section 8.1). Reading tolerates a byte order mark, which some
|
|
21
|
+
# producers emit; writing must not add one, so the two differ.
|
|
22
|
+
READ_ENCODING = "utf-8-sig"
|
|
23
|
+
WRITE_ENCODING = "utf-8"
|
|
24
|
+
|
|
20
25
|
|
|
21
26
|
class GeoJSON(BaseEncoding):
|
|
22
27
|
feature_properties = {"type", "id", "geometry", "bbox", "properties"}
|
|
@@ -152,7 +157,7 @@ class GeoJSON(BaseEncoding):
|
|
|
152
157
|
enforce_featurecollection: bool = False,
|
|
153
158
|
) -> Union[FeatureCollection, Feature]:
|
|
154
159
|
# num only applies to FeatureCollections
|
|
155
|
-
with open(self.uri, "r") as f:
|
|
160
|
+
with open(self.uri, "r", encoding=READ_ENCODING) as f:
|
|
156
161
|
obj = json.load(f)
|
|
157
162
|
|
|
158
163
|
if not isinstance(obj, dict):
|
|
@@ -233,7 +238,7 @@ class GeoJSON(BaseEncoding):
|
|
|
233
238
|
schema_map: SchemaMapping = {},
|
|
234
239
|
properties: Optional[list[str]] = None,
|
|
235
240
|
) -> GeoDataFrame:
|
|
236
|
-
with open(self.uri, "r") as f:
|
|
241
|
+
with open(self.uri, "r", encoding=READ_ENCODING) as f:
|
|
237
242
|
stream = json_stream.load(f)
|
|
238
243
|
data = {
|
|
239
244
|
"id": [],
|
|
@@ -291,7 +296,7 @@ class GeoJSON(BaseEncoding):
|
|
|
291
296
|
return gdf
|
|
292
297
|
|
|
293
298
|
def _write_json(self, obj, path, indent=None) -> bool:
|
|
294
|
-
with open(path, "w") as f:
|
|
299
|
+
with open(path, "w", encoding=WRITE_ENCODING) as f:
|
|
295
300
|
json.dump(obj, f, allow_nan=False, indent=indent, cls=VecorelJSONEncoder)
|
|
296
301
|
return True
|
|
297
302
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|