procodile 0.0.9__tar.gz → 0.1.1__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.
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: procodile
3
- Version: 0.0.9
3
+ Version: 0.1.1
4
4
  Summary: A light-weight processor development framework
5
5
  Project-URL: Documentation, https://eo-tools.github.io/eozilla
6
6
  Project-URL: Repository, https://github.com/eo-tools/eozilla
7
7
  Project-URL: Changelog, https://github.com/eo-tools/eozilla/blob/main/CHANGES.md
8
8
  Project-URL: Issues, https://github.com/eo-tools/eozilla/issues
9
- Author: Norman Fomferra (Brockmann Consult GmbH), Tejas Morbagal Harish (Brockmann Consult GmbH)
9
+ Author-email: b-yogesh <b-yogesh@users.noreply.github.com>, forman <forman@users.noreply.github.com>, pont-us <pont-us@users.noreply.github.com>, TejasMorbagal <TejasMorbagal@users.noreply.github.com>
10
10
  License: Apache-2.0
11
11
  License-File: LICENSE
12
12
  Keywords: data processing,eo,esa,ogc
@@ -19,15 +19,15 @@ Classifier: Operating System :: Microsoft :: Windows
19
19
  Classifier: Operating System :: POSIX
20
20
  Classifier: Operating System :: Unix
21
21
  Classifier: Programming Language :: Python :: 3
22
- Classifier: Programming Language :: Python :: 3.10
23
22
  Classifier: Programming Language :: Python :: 3.11
24
23
  Classifier: Programming Language :: Python :: 3.12
25
24
  Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Programming Language :: Python :: 3.14
26
26
  Classifier: Topic :: Scientific/Engineering
27
27
  Classifier: Topic :: Software Development
28
28
  Classifier: Typing :: Typed
29
29
  Requires-Python: >=3.10
30
- Requires-Dist: gavicore>=0.0.7
30
+ Requires-Dist: gavicore>=0.1.1
31
31
  Requires-Dist: pydantic
32
32
  Requires-Dist: pyyaml
33
33
  Requires-Dist: typer
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2025 by the Eozilla team and contributors
1
+ # Copyright (c) 2025-2026 by the Eozilla team and contributors
2
2
  # Permissions are hereby granted under the terms of the Apache 2.0 License:
3
3
  # https://opensource.org/license/apache-2-0.
4
4
 
@@ -10,7 +10,7 @@ from gavicore.util.request import ExecutionRequest
10
10
 
11
11
  from .artifacts import ArtifactRef, ArtifactStore, ExecutionContext
12
12
  from .job import Job, JobCancelledException, JobContext
13
- from .process import Process, additional_parameters
13
+ from .process import Process
14
14
  from .registry import ProcessRegistry
15
15
  from .workflow import (
16
16
  FromMain,
@@ -22,7 +22,6 @@ from .workflow import (
22
22
  """Processes development API."""
23
23
 
24
24
  __all__ = [
25
- "additional_parameters",
26
25
  "ArtifactRef",
27
26
  "ArtifactStore",
28
27
  "__version__",
@@ -1,3 +1,7 @@
1
+ # Copyright (c) 2026 by the Eozilla team and contributors
2
+ # Permissions are hereby granted under the terms of the Apache 2.0 License:
3
+ # https://opensource.org/license/apache-2-0.
4
+
1
5
  from abc import ABC, abstractmethod
2
6
  from dataclasses import dataclass
3
7
  from typing import Any, Mapping, TypeAlias
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2025 by the Eozilla team and contributors
1
+ # Copyright (c) 2025-2026 by the Eozilla team and contributors
2
2
  # Permissions are hereby granted under the terms of the Apache 2.0 License:
3
3
  # https://opensource.org/license/apache-2-0.
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2025 by the Eozilla team and contributors
1
+ # Copyright (c) 2025-2026 by the Eozilla team and contributors
2
2
  # Permissions are hereby granted under the terms of the Apache 2.0 License:
3
3
  # https://opensource.org/license/apache-2-0.
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2025 by the Eozilla team and contributors
1
+ # Copyright (c) 2025-2026 by the Eozilla team and contributors
2
2
  # Permissions are hereby granted under the terms of the Apache 2.0 License:
3
3
  # https://opensource.org/license/apache-2-0.
4
4
 
@@ -17,7 +17,6 @@ from gavicore.models import (
17
17
  JobInfo,
18
18
  JobResults,
19
19
  JobStatus,
20
- JobType,
21
20
  ProcessRequest,
22
21
  Schema,
23
22
  Subscriber,
@@ -195,9 +194,8 @@ class Job(JobContext):
195
194
  self.process = process
196
195
  # noinspection PyTypeChecker
197
196
  self.job_info = JobInfo( # noqa [call-arg]
198
- type=JobType.process,
199
- processID=process.description.id,
200
197
  jobID=job_id,
198
+ processID=process.description.id,
201
199
  status=JobStatus.accepted,
202
200
  created=self._now(),
203
201
  )
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2025 by the Eozilla team and contributors
1
+ # Copyright (c) 2025-2026 by the Eozilla team and contributors
2
2
  # Permissions are hereby granted under the terms of the Apache 2.0 License:
3
3
  # https://opensource.org/license/apache-2-0.
4
4
 
@@ -10,14 +10,13 @@ from pydantic import BaseModel, Field, ValidationError, create_model
10
10
  from pydantic.fields import FieldInfo
11
11
 
12
12
  from gavicore.models import (
13
- AdditionalParameter,
14
- AdditionalParameters,
15
13
  InputDescription,
16
14
  OutputDescription,
17
15
  ProcessDescription,
18
16
  Schema,
19
17
  )
20
- from gavicore.util.schema import create_schema_dict
18
+
19
+ from .schema import model_class_to_openapi_schema_dict
21
20
 
22
21
 
23
22
  @dataclass
@@ -133,31 +132,6 @@ class Process:
133
132
  )
134
133
 
135
134
 
136
- def additional_parameters(
137
- parameters: dict[str, Any], **metadata: Any
138
- ) -> AdditionalParameters:
139
- """
140
- Helper function that creates an instance of `AdditionalParameters`
141
- from the keys and values given the `parameters` dictionary.
142
- The return value is used as the `additionalParameters` argument of an
143
- `InputDescription` or `OutputDescription`.
144
-
145
- Args:
146
- parameters: the parameter key-value pairs.
147
- metadata: Other metadata fields passed to `AdditionalParameters`.
148
-
149
- Returns:
150
- A `AdditionalParameters` instance that can be passed to an
151
- `InputDescription` or `OutputDescription`.
152
- """
153
- return AdditionalParameters(
154
- parameters=[
155
- AdditionalParameter(name=k, value=[v]) for k, v in parameters.items()
156
- ],
157
- **metadata,
158
- )
159
-
160
-
161
135
  def _parse_inputs(
162
136
  fn_name: str,
163
137
  signature: inspect.Signature,
@@ -182,16 +156,20 @@ def _parse_inputs(
182
156
  model_class = create_model("ProcessInputs", **model_field_definitions)
183
157
 
184
158
  if inputs:
185
- model_class = _merge_inputs_into_model_class(
159
+ model_class_merged = _merge_inputs_into_model_class(
186
160
  fn_name=fn_name,
187
161
  signature=signature,
188
162
  inputs=inputs,
189
163
  model_class=model_class,
190
164
  )
165
+ # TODO: Work out why mypy dislikes this apparently valid assignment
166
+ model_class = model_class_merged # type:ignore[misc,assignment]
191
167
 
192
168
  model_class.model_rebuild()
193
169
 
194
- inputs_schema_dict: dict[str, Any] = create_schema_dict(model_class)
170
+ inputs_schema_dict: dict[str, Any] = model_class_to_openapi_schema_dict(
171
+ model_class, inline_refs=True
172
+ )
195
173
  required_names: list[str] = inputs_schema_dict.get("required", [])
196
174
  properties: dict[str, Any] = inputs_schema_dict.get("properties", {})
197
175
 
@@ -224,7 +202,9 @@ def _parse_outputs(
224
202
  fn_name, output_annotation, outputs
225
203
  )
226
204
  model_class = create_model("Outputs", **model_field_definitions) # type: ignore[call-overload]
227
- outputs_schema_dict = create_schema_dict(model_class)
205
+ outputs_schema_dict = model_class_to_openapi_schema_dict(
206
+ model_class, inline_refs=True
207
+ )
228
208
  properties = outputs_schema_dict.get("properties", {})
229
209
 
230
210
  output_descriptions: dict[str, OutputDescription] = {}
@@ -266,6 +246,12 @@ def _parse_parameters(
266
246
  return arg_parameters, job_ctx_arg
267
247
 
268
248
 
249
+ # TODO: replace deprecated FieldInfo.merge_field_infos()
250
+ # used in _merge_inputs_into_model_class(). See
251
+ # - https://github.com/pydantic/pydantic/issues/12329
252
+ # - https://github.com/pydantic/pydantic/issues/12374
253
+
254
+
269
255
  def _merge_inputs_into_model_class(
270
256
  fn_name: str,
271
257
  signature: inspect.Signature,
@@ -416,6 +402,7 @@ def _merge_input_descriptions(
416
402
  additionalParameters=(
417
403
  base_description.additionalParameters or description.additionalParameters
418
404
  ),
405
+ **(base_description.model_extra or {}),
419
406
  )
420
407
 
421
408
 
@@ -435,6 +422,7 @@ def _merge_output_descriptions(
435
422
  additionalParameters=(
436
423
  base_description.additionalParameters or description.additionalParameters
437
424
  ),
425
+ **(base_description.model_extra or {}),
438
426
  )
439
427
 
440
428
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2025 by the Eozilla team and contributors
1
+ # Copyright (c) 2025-2026 by the Eozilla team and contributors
2
2
  # Permissions are hereby granted under the terms of the Apache 2.0 License:
3
3
  # https://opensource.org/license/apache-2-0.
4
4
  import functools
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2025 by the Eozilla team and contributors
1
+ # Copyright (c) 2025-2026 by the Eozilla team and contributors
2
2
  # Permissions are hereby granted under the terms of the Apache 2.0 License:
3
3
  # https://opensource.org/license/apache-2-0.
4
4
 
@@ -0,0 +1,159 @@
1
+ # Copyright (c) 2025-2026 by the Eozilla team and contributors
2
+ # Permissions are hereby granted under the terms of the Apache 2.0 License:
3
+ # https://opensource.org/license/apache-2-0.
4
+
5
+ import copy
6
+ from collections.abc import Sequence
7
+ from typing import Any
8
+
9
+ import pydantic
10
+
11
+ from gavicore.util.ensure import ensure_condition
12
+
13
+
14
+ def model_class_to_openapi_schema_dict(
15
+ model_class: type[pydantic.BaseModel],
16
+ *,
17
+ inline_refs: bool = False,
18
+ openapi_spec: str = "3.0",
19
+ ) -> dict[str, Any]:
20
+ """
21
+ Convert a Pydantic model class to an OpenAPI schema `dict` object.
22
+
23
+ Args:
24
+ model_class: The Pydantic model class.
25
+ inline_refs: Whether to inline any references (`$ref` values)
26
+ generated by `model_class.model_json_schema()`.
27
+ openapi_spec: The OpenAPI specification.
28
+ Currently, only `"3.0"` is supported.
29
+ Returns:
30
+ An OpenAPI schema `dict` object.
31
+ """
32
+ model_class.model_rebuild()
33
+ schema = model_class.model_json_schema()
34
+ if inline_refs:
35
+ schema = inline_schema_refs(schema)
36
+ return json_schema_to_openapi_schema(schema, openapi_spec=openapi_spec)
37
+
38
+
39
+ def inline_schema_refs(schema: dict[str, Any] | bool) -> Any:
40
+ if not isinstance(schema, dict):
41
+ return schema
42
+ defs: dict[str, Any] | None = schema.get("$defs")
43
+ if not defs:
44
+ return schema
45
+ schema = copy.copy(schema)
46
+ schema.pop("$defs")
47
+ return _inline_schema_refs(schema, {f"#/$defs/{k}": v for k, v in defs.items()})
48
+
49
+
50
+ def _inline_schema_refs(schema: dict[str, Any] | bool, defs: dict[str, Any]) -> Any:
51
+ if not isinstance(schema, dict):
52
+ return schema
53
+ if "$ref" in schema:
54
+ ref = schema["$ref"]
55
+ if ref in defs:
56
+ ref_schema = _inline_schema_refs(defs[ref], defs)
57
+ schema = copy.copy(schema)
58
+ schema.pop("$ref")
59
+ schema.update(copy.deepcopy(ref_schema))
60
+ return schema
61
+ schema = copy.copy(schema)
62
+ for k in ("allOf", "anyOf", "oneOf"):
63
+ if k in schema:
64
+ if isinstance(schema[k], list):
65
+ schema[k] = [_inline_schema_refs(s, defs) for s in schema[k]]
66
+ for k in ("items", "prefixItems", "additionalProperties"):
67
+ if k in schema:
68
+ if isinstance(schema[k], list):
69
+ schema[k] = [_inline_schema_refs(s, defs) for s in schema[k]]
70
+ else:
71
+ schema[k] = _inline_schema_refs(schema[k], defs)
72
+ for k in ("properties",):
73
+ if k in schema:
74
+ if isinstance(schema[k], dict):
75
+ schema[k] = {
76
+ k: _inline_schema_refs(s, defs) for k, s in schema[k].items()
77
+ }
78
+ return schema
79
+
80
+
81
+ def json_schema_to_openapi_schema(
82
+ schema: dict[str, Any], *, openapi_spec: str = "3.0"
83
+ ) -> dict[str, Any]:
84
+ """
85
+ Convert a JSON schema `dict` object into an OpenAPI schema `dict` object.
86
+
87
+ Args:
88
+ schema: A JSON schema `dict` object.
89
+ openapi_spec: The OpenAPI specification.
90
+ Currently, only `"3.0"` is supported.
91
+ Returns:
92
+ An OpenAPI schema `dict` object.
93
+ """
94
+ ensure_condition(openapi_spec == "3.0", "openapi_spec must be '3.0'")
95
+ return _json_schema_to_openapi_schema_3_0(copy.deepcopy(schema))
96
+
97
+
98
+ def _json_schema_to_openapi_schema_3_0(schema: dict[str, Any]) -> dict[str, Any]:
99
+ if "type" in schema:
100
+ type_ = schema["type"]
101
+ if type_ == "null":
102
+ schema.pop("type")
103
+ schema["nullable"] = True
104
+ if "prefixItems" in schema:
105
+ # This is how pydantic encodes tuples.
106
+ items = schema.pop("prefixItems")
107
+ if isinstance(items, (list, tuple)):
108
+ schema["items"] = _json_tuple_to_openapi_items_3_0(items)
109
+ if "items" in schema:
110
+ items = schema.pop("items")
111
+ if isinstance(items, (list, tuple)):
112
+ schema["items"] = _json_tuple_to_openapi_items_3_0(items)
113
+ elif isinstance(items, dict):
114
+ schema["items"] = _json_schema_to_openapi_schema_3_0(items)
115
+ if "additionalProperties" in schema:
116
+ additional_properties = schema.pop("additionalProperties")
117
+ if isinstance(additional_properties, dict):
118
+ schema["additionalProperties"] = _json_schema_to_openapi_schema_3_0(
119
+ additional_properties
120
+ )
121
+ elif additional_properties in (True, None):
122
+ schema["additionalProperties"] = {}
123
+ elif additional_properties is False:
124
+ schema["additionalProperties"] = False
125
+ for dict_key in ("properties", "$defs"):
126
+ if dict_key in schema and isinstance(schema[dict_key], dict):
127
+ schema[dict_key] = {
128
+ k: _json_schema_to_openapi_schema_3_0(v)
129
+ for k, v in schema[dict_key].items()
130
+ }
131
+ for x_of_key in ("allOf", "anyOf", "oneOf"):
132
+ if x_of_key in schema:
133
+ schema[x_of_key] = list(
134
+ map(_json_schema_to_openapi_schema_3_0, schema[x_of_key])
135
+ )
136
+ if len(schema[x_of_key]) == 2:
137
+ x_of_copy = [s for s in schema[x_of_key] if s != {"nullable": True}]
138
+ if len(x_of_copy) == 1:
139
+ schema.pop(x_of_key)
140
+ schema.update(x_of_copy[0])
141
+ schema["nullable"] = True
142
+ return schema
143
+
144
+
145
+ def _json_tuple_to_openapi_items_3_0(
146
+ tuple_schemas: Sequence[dict[str, Any]],
147
+ ) -> dict[str, Any]:
148
+ """Convert a JSON schema tuple."""
149
+ if not tuple_schemas:
150
+ return {}
151
+ converted = [_json_schema_to_openapi_schema_3_0(v) for v in tuple_schemas]
152
+ c0 = converted[0]
153
+ if all(c == c0 for c in converted[1:]):
154
+ # If all items are the same schema,
155
+ # we can take the first.
156
+ return c0
157
+ # As there is no way to represent tuples in OpenAPI <= 3.1,
158
+ # we set items to oneOf of all tuple member schemas.
159
+ return {"oneOf": converted}
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2025 by the Eozilla team and contributors
1
+ # Copyright (c) 2025-2026 by the Eozilla team and contributors
2
2
  # Permissions are hereby granted under the terms of the Apache 2.0 License:
3
3
  # https://opensource.org/license/apache-2-0.
4
4
 
@@ -4,12 +4,14 @@
4
4
 
5
5
  [project]
6
6
  name = "procodile"
7
- version = "0.0.9"
7
+ version = "0.1.1"
8
8
  description = "A light-weight processor development framework"
9
9
  readme = "README.md"
10
10
  authors = [
11
- {name = "Norman Fomferra (Brockmann Consult GmbH)"},
12
- {name = "Tejas Morbagal Harish (Brockmann Consult GmbH)"}
11
+ {name = "b-yogesh", email = "b-yogesh@users.noreply.github.com"},
12
+ {name = "forman", email = "forman@users.noreply.github.com"},
13
+ {name = "pont-us", email = "pont-us@users.noreply.github.com"},
14
+ {name = "TejasMorbagal", email = "TejasMorbagal@users.noreply.github.com"},
13
15
  ]
14
16
  keywords = [
15
17
  "eo",
@@ -24,10 +26,10 @@ classifiers = [
24
26
  "Intended Audience :: Developers",
25
27
  "License :: OSI Approved :: Apache Software License",
26
28
  "Programming Language :: Python :: 3",
27
- "Programming Language :: Python :: 3.10",
28
29
  "Programming Language :: Python :: 3.11",
29
30
  "Programming Language :: Python :: 3.12",
30
31
  "Programming Language :: Python :: 3.13",
32
+ "Programming Language :: Python :: 3.14",
31
33
  "Topic :: Software Development",
32
34
  "Topic :: Scientific/Engineering",
33
35
  "Typing :: Typed",
@@ -42,7 +44,7 @@ dependencies = [
42
44
  "pyyaml",
43
45
  "typer",
44
46
  # local dependency
45
- "gavicore>=0.0.7",
47
+ "gavicore >=0.1.1",
46
48
  ]
47
49
 
48
50
  [project.urls]
File without changes
File without changes
File without changes
File without changes