pproc-core 0.1.0__py3-none-any.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.
Files changed (55) hide show
  1. earthkit/workflows/plugins/pproc/__init__.py +0 -0
  2. earthkit/workflows/plugins/pproc/_version.py +2 -0
  3. earthkit/workflows/plugins/pproc/config/accumulation.py +58 -0
  4. earthkit/workflows/plugins/pproc/config/mask.py +25 -0
  5. earthkit/workflows/plugins/pproc/config/threshold.py +47 -0
  6. earthkit/workflows/plugins/pproc/fluent.py +822 -0
  7. earthkit/workflows/plugins/pproc/metadata/accumulation.py +56 -0
  8. earthkit/workflows/plugins/pproc/metadata/threshold.py +99 -0
  9. earthkit/workflows/plugins/pproc/utils/__init__.py +0 -0
  10. earthkit/workflows/plugins/pproc/utils/metadata.py +31 -0
  11. earthkit/workflows/plugins/pproc/utils/pydantic_utils.py +9 -0
  12. earthkit/workflows/plugins/pproc/utils/request.py +117 -0
  13. ppcore/__init__.py +0 -0
  14. ppcore/config.py +295 -0
  15. ppcore/configs/__init__.py +80 -0
  16. ppcore/configs/common/__init__.py +0 -0
  17. ppcore/configs/common/accumulation.py +145 -0
  18. ppcore/configs/common/input.py +71 -0
  19. ppcore/configs/common/output.py +58 -0
  20. ppcore/configs/common/preprocessing.py +100 -0
  21. ppcore/configs/common/source.py +35 -0
  22. ppcore/configs/common/stats.py +48 -0
  23. ppcore/configs/common/target.py +42 -0
  24. ppcore/configs/entrypoint/base.py +46 -0
  25. ppcore/configs/entrypoint/execution.py +11 -0
  26. ppcore/configs/entrypoint/log.py +26 -0
  27. ppcore/configs/product/__init__.py +59 -0
  28. ppcore/configs/product/ensemble.py +71 -0
  29. ppcore/product.py +34 -0
  30. ppcore/products/__init__.py +138 -0
  31. ppcore/products/base.py +22 -0
  32. ppcore/products/ensemble.py +153 -0
  33. ppcore/schema/__init__.py +3 -0
  34. ppcore/schema/base.py +311 -0
  35. ppcore/schema/config.py +63 -0
  36. ppcore/schema/deriver.py +296 -0
  37. ppcore/schema/filters.py +37 -0
  38. ppcore/schema/forecast.py +281 -0
  39. ppcore/schema/input.py +416 -0
  40. ppcore/schema/schema.py +109 -0
  41. ppcore/schema/step.py +133 -0
  42. ppcore/utils/dicts.py +44 -0
  43. ppcore/utils/entrypoint.py +25 -0
  44. ppcore/utils/helpers.py +13 -0
  45. ppcore/utils/io.py +17 -0
  46. ppcore/utils/mars.py +77 -0
  47. ppcore/utils/qube.py +27 -0
  48. ppcore/utils/requests.py +148 -0
  49. ppcore/utils/stepseq.py +70 -0
  50. pproc_core-0.1.0.dist-info/METADATA +47 -0
  51. pproc_core-0.1.0.dist-info/RECORD +55 -0
  52. pproc_core-0.1.0.dist-info/WHEEL +5 -0
  53. pproc_core-0.1.0.dist-info/entry_points.txt +3 -0
  54. pproc_core-0.1.0.dist-info/licenses/LICENSE +79 -0
  55. pproc_core-0.1.0.dist-info/top_level.txt +2 -0
File without changes
@@ -0,0 +1,2 @@
1
+ # Do not change! Do not track in version control!
2
+ __version__ = "0.1.0"
@@ -0,0 +1,58 @@
1
+ # SPDX-FileCopyrightText: 2026 European Centre for Medium-Range Weather Forecasts (ECMWF)
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ from typing import Literal, Optional, Union, Annotated
6
+ import datetime
7
+
8
+ from earthkit.time.calendar import MonthInYear
9
+ from earthkit.time.sequence import MonthlySequence
10
+
11
+ from pydantic import Field, ConfigDict
12
+
13
+ from earthkit.workflows.plugins.pproc.utils.pydantic_utils import PProcBaseModel
14
+
15
+ NumericCoord = int
16
+ NumericCoords = Union[list[int], range]
17
+
18
+ Coord = Union[str, NumericCoord]
19
+ Coords = Union[list[str], NumericCoords]
20
+
21
+
22
+ class Default(PProcBaseModel):
23
+ model_config = ConfigDict(validate_by_name=True)
24
+
25
+ type_: Literal["default"] = Field("default", alias="type")
26
+ length: Optional[int] = None
27
+
28
+ def name(self, coords: Coords) -> str:
29
+ if len(coords) == 0:
30
+ return ""
31
+ end = coords[-1]
32
+ if len(coords) == 1 and (self.length is None or isinstance(coords[0], str)):
33
+ return f"{end}"
34
+ start = coords[0] if self.length is None else int(end) - self.length
35
+ return f"{start}-{end}"
36
+
37
+
38
+ class Monthly(PProcBaseModel):
39
+ model_config = ConfigDict(validate_by_name=True)
40
+
41
+ type_: Literal["monthly"] = Field("monthly", alias="type")
42
+ date: str
43
+
44
+ def name(self, coords: Coords) -> str:
45
+ if len(coords) == 0:
46
+ return ""
47
+ end = coords[-1]
48
+ fcdate = datetime.datetime.strptime(self.date, "%Y%m%d")
49
+ end = int(end)
50
+ seq = MonthlySequence(1)
51
+ seq.next(fcdate, False)
52
+ this_month = fcdate + datetime.timedelta(hours=end - 1)
53
+ month_length = MonthInYear(this_month.year, this_month.month).length() * 24
54
+ start = end - month_length
55
+ return f"{start}-{end}"
56
+
57
+
58
+ AccumName = Annotated[Union[Default, Monthly], Field(discriminator="type")]
@@ -0,0 +1,25 @@
1
+ # SPDX-FileCopyrightText: 2026 European Centre for Medium-Range Weather Forecasts (ECMWF)
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ from typing import Any, Literal
6
+
7
+ from pydantic import model_validator
8
+
9
+ from earthkit.workflows.plugins.pproc.utils.pydantic_utils import PProcBaseModel
10
+
11
+
12
+ class MaskExpression(PProcBaseModel):
13
+ select: dict
14
+ comparison: Literal["<", ">", ">=", "<=", "==", "!="]
15
+ value: float
16
+
17
+ @model_validator(mode="before")
18
+ @classmethod
19
+ def validate_model(cls, data: Any) -> Any:
20
+ if isinstance(data, list):
21
+ assert (
22
+ len(data) == 3
23
+ ), "Mask expression should be a [select, comparison, value] list"
24
+ return {"select": data[0], "comparison": data[1], "value": data[2]}
25
+ return data
@@ -0,0 +1,47 @@
1
+ # SPDX-FileCopyrightText: 2026 European Centre for Medium-Range Weather Forecasts (ECMWF)
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ from pydantic import model_validator
6
+ from typing import Any, Optional, Literal
7
+
8
+ from earthkit.workflows.plugins.pproc.utils.pydantic_utils import PProcBaseModel
9
+
10
+ Comparisons = Literal["<", ">", "<=", ">="]
11
+
12
+
13
+ class Threshold(PProcBaseModel):
14
+ select: Optional[dict] = None
15
+ lower_scale_factor: int = 0
16
+ lower_comparison: Comparisons
17
+ lower_value: float
18
+ upper_scale_factor: int = 0
19
+ upper_comparison: Optional[Comparisons] = None
20
+ upper_value: Optional[float] = None
21
+
22
+ @model_validator(mode="before")
23
+ def validate_threshold(cls, data: Any) -> Any:
24
+ if isinstance(data, dict):
25
+ if "comparison" in data:
26
+ data["lower_comparison"] = data.pop("comparison")
27
+ data["lower_value"] = data.pop("value")
28
+ data["lower_scale_factor"] = data.pop("scale_factor", 0)
29
+ if any(k in data for k in ["upper_comparison", "upper_value"]) and not all(
30
+ k in data for k in ["upper_comparison", "upper_value"]
31
+ ):
32
+ raise ValueError(
33
+ "Both upper_comparison and upper_value must be provided together"
34
+ )
35
+ # Derive scale factors for custom thresholds
36
+ for value in ["lower_value", "upper_value"]:
37
+ upper_or_lower = value.split("_")[0]
38
+ if (
39
+ isinstance(data.get(value), float)
40
+ and f"{upper_or_lower}_scale_factor" not in data
41
+ ):
42
+ scale_factor = 0
43
+ while abs(data[value] * 10**scale_factor) < 1:
44
+ scale_factor += 1
45
+ data[f"{upper_or_lower}_scale_factor"] = scale_factor
46
+ data[value] = round(data[value] * 10**scale_factor)
47
+ return data