covjsonkit 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.
Files changed (109) hide show
  1. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/PKG-INFO +1 -1
  2. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/encoder.py +13 -3
  3. covjsonkit-0.2.17/covjsonkit/version.py +1 -0
  4. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit.egg-info/PKG-INFO +1 -1
  5. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit.egg-info/SOURCES.txt +1 -0
  6. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/pyproject.toml +1 -1
  7. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/conftest.py +1 -1
  8. covjsonkit-0.2.17/tests/geojsontest.py +16 -0
  9. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_bounding_box_from_polytope.py +1 -1
  10. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_position_from_polytope.py +2 -2
  11. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_time_series_from_polytope.py +43 -4
  12. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_vertical_profile_from_polytope.py +1 -1
  13. covjsonkit-0.2.16/covjsonkit/version.py +0 -1
  14. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/.github/ci-hpc-config.yml +0 -0
  15. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/.github/workflows/ci.yaml +0 -0
  16. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/.github/workflows/label-public-pr.yml +0 -0
  17. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/.gitignore +0 -0
  18. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/.pre-commit-config.yaml +0 -0
  19. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/ACKNOWLEDGEMENTS.rst +0 -0
  20. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/LICENSE +0 -0
  21. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/MANIFEST.in +0 -0
  22. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/Makefile +0 -0
  23. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/README.md +0 -0
  24. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/Coverage.py +0 -0
  25. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/CoverageCollection.py +0 -0
  26. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/__init__.py +0 -0
  27. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/api.py +0 -0
  28. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/config.py +0 -0
  29. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/data/__init__.py +0 -0
  30. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/data/dwd/param.json +0 -0
  31. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/data/dwd/param_id.json +0 -0
  32. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/data/dwd/unit.json +0 -0
  33. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/data/ecmwf/param.json +0 -0
  34. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/data/ecmwf/param_id.json +0 -0
  35. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/data/ecmwf/unit.json +0 -0
  36. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/BoundingBox.py +0 -0
  37. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/Circle.py +0 -0
  38. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/Frame.py +0 -0
  39. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/Grid.py +0 -0
  40. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/Path.py +0 -0
  41. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/Position.py +0 -0
  42. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/Shapefile.py +0 -0
  43. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/TimeSeries.py +0 -0
  44. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/VerticalProfile.py +0 -0
  45. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/Wkt.py +0 -0
  46. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/__init__.py +0 -0
  47. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/decoder/decoder.py +0 -0
  48. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/BoundingBox.py +0 -0
  49. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/Circle.py +0 -0
  50. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/Frame.py +0 -0
  51. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/Grid.py +0 -0
  52. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/Path.py +0 -0
  53. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/Position.py +0 -0
  54. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/Shapefile.py +0 -0
  55. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/TimeSeries.py +0 -0
  56. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/VerticalProfile.py +0 -0
  57. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/Wkt.py +0 -0
  58. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/encoder/__init__.py +0 -0
  59. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/param_db.py +0 -0
  60. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit/utils.py +0 -0
  61. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit.egg-info/dependency_links.txt +0 -0
  62. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit.egg-info/not-zip-safe +0 -0
  63. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit.egg-info/requires.txt +0 -0
  64. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/covjsonkit.egg-info/top_level.txt +0 -0
  65. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/docs/images/ECMWF_logo.svg.png +0 -0
  66. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/docs/images/Logo_Destination_Earth_Colours.png +0 -0
  67. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/example_config.json +0 -0
  68. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/requirements.txt +0 -0
  69. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/scripts/generate_param_db.py +0 -0
  70. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/setup.cfg +0 -0
  71. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/setup.py +0 -0
  72. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/data/test_coverage1.json +0 -0
  73. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/data/test_coverage2.json +0 -0
  74. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/data/test_geotiff.json +0 -0
  75. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/data/test_multipoint_coverage.json +0 -0
  76. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/data/test_path_coverage.json +0 -0
  77. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/data/test_timeseries_coverage.json +0 -0
  78. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/data/test_timeseries_xyz_coverage.json +0 -0
  79. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/data/test_verticalprofile_coverage.json +0 -0
  80. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/data/test_verticalprofile_xyz_coverage.json +0 -0
  81. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/requirements_test.txt +0 -0
  82. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_decoder_bounding_box.py +0 -0
  83. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_decoder_frame.py +0 -0
  84. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_decoder_grid.py +0 -0
  85. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_decoder_shapefile.py +0 -0
  86. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_decoder_time_series.py +0 -0
  87. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_decoder_vertical_profile.py +0 -0
  88. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_decoder_wkt.py +0 -0
  89. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_bounding_box.py +0 -0
  90. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_circle_from_polytope.py +0 -0
  91. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_frame.py +0 -0
  92. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_frame_from_polytope.py +0 -0
  93. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_grid.py +0 -0
  94. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_grid_from_polytope.py +0 -0
  95. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_path.py +0 -0
  96. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_path_from_polytope.py +0 -0
  97. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_shapefile.py +0 -0
  98. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_shapefile_from_polytope.py +0 -0
  99. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_time_series.py +0 -0
  100. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_wkt.py +0 -0
  101. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_encoder_wkt_from_polytope.py +0 -0
  102. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_geojson.py +0 -0
  103. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_geotiff.py +0 -0
  104. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_util_merge.py +0 -0
  105. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_xarray_multipoint.py +0 -0
  106. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_xarray_path.py +0 -0
  107. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_xarray_ts.py +0 -0
  108. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tests/test_xarray_vp.py +0 -0
  109. {covjsonkit-0.2.16 → covjsonkit-0.2.17}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: covjsonkit
3
- Version: 0.2.16
3
+ Version: 0.2.17
4
4
  Home-page: https://github.com/ecmwf/covjsonkit
5
5
  Author: ECMWF
6
6
  Author-email: James.Hawkes@ecmwf.int, Adam.Warde@ecmwf.int, Mathilde.Leuridan@ecmwf.int
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from abc import ABC, abstractmethod
4
4
  from typing import Any
5
5
 
6
+ import numpy as np
6
7
  import orjson
7
8
  import pandas as pd
8
9
  from covjson_pydantic.coverage import CoverageCollection
@@ -176,7 +177,10 @@ class Encoder(ABC):
176
177
  def handle_non_leaf_node(child):
177
178
  non_leaf_axes = ["latitude", "longitude", "param", date_key]
178
179
  if child.axis.name not in non_leaf_axes:
179
- mars_metadata[child.axis.name] = child.values[0]
180
+ val = child.values[0]
181
+ if isinstance(val, np.datetime64):
182
+ val = str(val)
183
+ mars_metadata[child.axis.name] = val
180
184
 
181
185
  def handle_specific_axes(child):
182
186
  if child.axis.name == "latitude":
@@ -272,7 +276,10 @@ class Encoder(ABC):
272
276
  def handle_non_leaf_node_step(child):
273
277
  non_leaf_axes = ["latitude", "longitude", "param", "date", "time"]
274
278
  if child.axis.name not in non_leaf_axes:
275
- mars_metadata[child.axis.name] = child.values[0]
279
+ val = child.values[0]
280
+ if isinstance(val, np.datetime64):
281
+ val = str(val)
282
+ mars_metadata[child.axis.name] = val
276
283
 
277
284
  def handle_specific_axes_step(child):
278
285
  if child.axis.name == "latitude":
@@ -441,7 +448,10 @@ class Encoder(ABC):
441
448
  def handle_non_leaf_node_month(child):
442
449
  non_leaf_axes = ["latitude", "longitude", "param", "year", "month"]
443
450
  if child.axis.name not in non_leaf_axes:
444
- mars_metadata[child.axis.name] = child.values[0]
451
+ val = child.values[0]
452
+ if isinstance(val, np.datetime64):
453
+ val = str(val)
454
+ mars_metadata[child.axis.name] = val
445
455
 
446
456
  def handle_specific_axes_month(child):
447
457
  if child.axis.name == "latitude":
@@ -0,0 +1 @@
1
+ __version__ = "0.2.17"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: covjsonkit
3
- Version: 0.2.16
3
+ Version: 0.2.17
4
4
  Home-page: https://github.com/ecmwf/covjsonkit
5
5
  Author: ECMWF
6
6
  Author-email: James.Hawkes@ecmwf.int, Adam.Warde@ecmwf.int, Mathilde.Leuridan@ecmwf.int
@@ -62,6 +62,7 @@ docs/images/ECMWF_logo.svg.png
62
62
  docs/images/Logo_Destination_Earth_Colours.png
63
63
  scripts/generate_param_db.py
64
64
  tests/conftest.py
65
+ tests/geojsontest.py
65
66
  tests/requirements_test.txt
66
67
  tests/test_decoder_bounding_box.py
67
68
  tests/test_decoder_frame.py
@@ -8,7 +8,7 @@ markers = ["data: uses test data (deselect with '-m \"not data\"')",]
8
8
 
9
9
  [project]
10
10
  name = "covjsonkit"
11
- version = "0.2.16"
11
+ version = "0.2.17"
12
12
  dependencies = [
13
13
  "pandas<3",
14
14
  "orjson",
@@ -6,7 +6,7 @@ from polytope_feature.datacube.tensor_index_tree import TensorIndexTree
6
6
 
7
7
  REFORECAST_METADATA_BASE = {
8
8
  "class": "ce",
9
- "date": np.datetime64("2024-03-01"),
9
+ "date": "2024-03-01",
10
10
  "domain": "g",
11
11
  "expver": "4321",
12
12
  "levtype": "sfc",
@@ -0,0 +1,16 @@
1
+ import json
2
+ import os
3
+
4
+ from covjsonkit.api import Covjsonkit
5
+
6
+ current_dir = os.path.dirname(__file__)
7
+ timeseries = os.path.join(current_dir, "data/test_timeseries_coverage.json")
8
+ with open(timeseries, "r") as f:
9
+ timeseries = json.load(f)
10
+
11
+
12
+ cov = Covjsonkit().decode(timeseries)
13
+ ts = cov.to_geojson()
14
+ print(ts)
15
+ assert ts["type"] == "FeatureCollection"
16
+ assert len(ts["features"]) == 16
@@ -22,7 +22,7 @@ COMPOSITE_TWO_POINTS = {
22
22
 
23
23
  EXPECTED_REFORECAST_METADATA = {
24
24
  "class": "ce",
25
- "date": np.datetime64("2024-03-01"),
25
+ "date": "2024-03-01",
26
26
  "domain": "g",
27
27
  "expver": "4321",
28
28
  "levtype": "sfc",
@@ -130,7 +130,7 @@ class TestPositionFromPolytopeReforecast:
130
130
 
131
131
  shared_metadata = {
132
132
  "class": "ce",
133
- "date": np.datetime64("2024-03-01"),
133
+ "date": "2024-03-01",
134
134
  "Forecast date": "2025-07-14T06:00:00Z",
135
135
  "domain": "g",
136
136
  "expver": "4321",
@@ -168,7 +168,7 @@ class TestPositionFromPolytopeReforecast:
168
168
 
169
169
  shared_metadata = {
170
170
  "class": "ce",
171
- "date": np.datetime64("2024-03-01"),
171
+ "date": "2024-03-01",
172
172
  "domain": "g",
173
173
  "expver": "4321",
174
174
  "levtype": "sfc",
@@ -1,4 +1,8 @@
1
+ import json
2
+
1
3
  import numpy as np
4
+ import orjson
5
+ import pytest
2
6
  from conftest import chain, make_leaf, make_point, node, tip
3
7
  from polytope_feature.datacube.tensor_index_tree import TensorIndexTree
4
8
 
@@ -29,7 +33,7 @@ def hdate_branch(hdate, lat, lon, result):
29
33
 
30
34
  EXPECTED_HDATE_METADATA = {
31
35
  "class": "ce",
32
- "date": np.datetime64("2024-03-01"),
36
+ "date": "2024-03-01",
33
37
  "domain": "g",
34
38
  "expver": "4321",
35
39
  "levtype": "sfc",
@@ -199,12 +203,13 @@ class TestTimeseriesFromPolytope:
199
203
 
200
204
 
201
205
  class TestTimeseriesFromPolytopeReforecast:
202
- def test_single_point(self):
206
+ @pytest.mark.parametrize("date", [np.datetime64("2024-03-01"), np.datetime64("2024-03-01T00:00:00")])
207
+ def test_single_point(self, date):
203
208
  # 1 hdate (with time pre-merged by polytope-mars), 1 point
204
209
  tree = chain(
205
210
  TensorIndexTree(),
206
211
  node("class", ("ce",)),
207
- node("date", (np.datetime64("2024-03-01"),)),
212
+ node("date", (date,)),
208
213
  hdate_branch(np.datetime64("2025-07-14T06:00:00"), 51.5, 6.5, [42.17]),
209
214
  )
210
215
 
@@ -231,7 +236,11 @@ class TestTimeseriesFromPolytopeReforecast:
231
236
  }
232
237
  }
233
238
 
234
- assert cov["mars:metadata"] == {"Forecast date": "2025-07-14T06:00:00Z", **EXPECTED_HDATE_METADATA}
239
+ assert cov["mars:metadata"] == {
240
+ "Forecast date": "2025-07-14T06:00:00Z",
241
+ **EXPECTED_HDATE_METADATA,
242
+ "date": date.astype(str),
243
+ }
235
244
 
236
245
  def test_multiple_times(self):
237
246
  # 2 hdate values (pre-merged times from same day), 1 point → 2 coverages
@@ -453,3 +462,33 @@ class TestTimeseriesFromPolytopeReforecast:
453
462
  assert cov["domain"]["axes"]["t"]["values"] == t
454
463
  assert cov["ranges"]["dis06"]["values"] == vals
455
464
  assert cov["mars:metadata"] == {"Forecast date": fc_date, **EXPECTED_HDATE_METADATA}
465
+
466
+ @pytest.mark.parametrize(
467
+ "json_module,date", [(json, np.datetime64("2024-03-01")), (orjson, np.datetime64("2024-03-01T00:00:00"))]
468
+ )
469
+ def test_reforecast_covjson_is_json_serialisable(self, json_module, date):
470
+ """CoverageJSON produced by from_polytope_reforecast must be serialisable
471
+ with both stdlib json and orjson (i.e. no numpy.datetime64 left in the
472
+ mars:metadata dict — regression test for the date axis leak)."""
473
+ tree = chain(
474
+ TensorIndexTree(),
475
+ node("class", ("ce",)),
476
+ node("date", (date,)),
477
+ hdate_branch(np.datetime64("2025-07-14T06:00:00"), 51.5, 6.5, [42.17]),
478
+ )
479
+
480
+ covjson = Covjsonkit().encode("CoverageCollection", "PointSeries").from_polytope_reforecast(tree)
481
+
482
+ # stdlib json.dumps must not raise TypeError
483
+ serialised = json_module.dumps(covjson)
484
+
485
+ # The 'date' value in mars:metadata must be a plain string, not numpy.datetime64
486
+ for cov in covjson["coverages"]:
487
+ date_val = cov["mars:metadata"].get("date")
488
+ assert not isinstance(
489
+ date_val, np.datetime64
490
+ ), f"mars:metadata['date'] is still a numpy.datetime64: {date_val!r}"
491
+
492
+ # Round-trip through the JSON module to ensure it can be deserialised back to a dict
493
+ deserialised = json_module.loads(serialised)
494
+ assert deserialised == covjson
@@ -200,7 +200,7 @@ class TestVerticalProfileFromPolytopeReforecast:
200
200
 
201
201
  EXPECTED_REFORECAST_METADATA = {
202
202
  "class": "ce",
203
- "date": np.datetime64("2024-03-01"),
203
+ "date": "2024-03-01",
204
204
  "domain": "g",
205
205
  "expver": "4321",
206
206
  "levtype": "pl",
@@ -1 +0,0 @@
1
- __version__ = "0.2.16"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes