Skip to content

Commit 65ac1c1

Browse files
authored
Fix: Model Validation not being strict. (#88)
1 parent 2c17def commit 65ac1c1

File tree

4 files changed

+57
-20
lines changed

4 files changed

+57
-20
lines changed

openeo_pg_parser_networkx/graph.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def _parse_datamodel(nested_graph: dict) -> ProcessGraph:
113113
Parses a nested process graph into the Pydantic datamodel for ProcessGraph.
114114
"""
115115

116-
return ProcessGraph.model_validate(nested_graph)
116+
return ProcessGraph.model_validate(nested_graph, strict=True)
117117

118118
def _parse_process_graph(self, process_graph: ProcessGraph, arg_name: str = None):
119119
"""
@@ -187,11 +187,11 @@ def _parse_argument(self, arg: any, arg_name: str, access_func: Callable):
187187

188188
# This access func business is necessary to let the program "remember" how to access and thus update this reference later
189189
sub_access_func = partial(
190-
lambda key, access_func, new_value=None, set_bool=False: access_func()[
191-
key
192-
]
193-
if not set_bool
194-
else access_func().__setitem__(key, new_value),
190+
lambda key, access_func, new_value=None, set_bool=False: (
191+
access_func()[key]
192+
if not set_bool
193+
else access_func().__setitem__(key, new_value)
194+
),
195195
key=k,
196196
access_func=access_func,
197197
)
@@ -205,11 +205,11 @@ def _parse_argument(self, arg: any, arg_name: str, access_func: Callable):
205205
parsed_arg = parse_nested_parameter(element)
206206

207207
sub_access_func = partial(
208-
lambda key, access_func, new_value=None, set_bool=False: access_func()[
209-
key
210-
]
211-
if not set_bool
212-
else access_func().__setitem__(key, new_value),
208+
lambda key, access_func, new_value=None, set_bool=False: (
209+
access_func()[key]
210+
if not set_bool
211+
else access_func().__setitem__(key, new_value)
212+
),
213213
key=i,
214214
access_func=access_func,
215215
)
@@ -246,12 +246,12 @@ def _walk_node(self):
246246

247247
# This just points to the resolved_kwarg itself!
248248
access_func = partial(
249-
lambda node_uid, arg_name, new_value=None, set_bool=False: self.G.nodes[
250-
node_uid
251-
]["resolved_kwargs"][arg_name]
252-
if not set_bool
253-
else self.G.nodes[node_uid]["resolved_kwargs"].__setitem__(
254-
arg_name, new_value
249+
lambda node_uid, arg_name, new_value=None, set_bool=False: (
250+
self.G.nodes[node_uid]["resolved_kwargs"][arg_name]
251+
if not set_bool
252+
else self.G.nodes[node_uid]["resolved_kwargs"].__setitem__(
253+
arg_name, new_value
254+
)
255255
),
256256
node_uid=self._EVAL_ENV.node_uid,
257257
arg_name=arg_name,

openeo_pg_parser_networkx/pg_schema.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
RootModel,
2626
StringConstraints,
2727
ValidationError,
28-
conlist,
2928
constr,
3029
field_validator,
3130
model_validator,
@@ -259,7 +258,9 @@ def __repr__(self):
259258

260259

261260
class TemporalInterval(RootModel):
262-
root: conlist(Union[Year, Date, DateTime, Time, None], min_length=2, max_length=2)
261+
root: Annotated[
262+
list[Union[Year, Date, DateTime, Time, None]], Field(min_length=2, max_length=2)
263+
]
263264

264265
@field_validator("root")
265266
def validate_temporal_interval(cls, value: Any) -> Any:

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "openeo-pg-parser-networkx"
3-
version = "2024.5.0"
3+
version = "2024.7.0"
44

55
description = "Parse OpenEO process graphs from JSON to traversible Python objects."
66
authors = ["Lukas Weidenholzer <[email protected]>", "Sean Hoyal <[email protected]>", "Valentina Hutter <[email protected]>", "Gerald Irsiegler <[email protected]>"]

tests/test_pg_parser.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,42 @@ def test_bounding_box_with_faulty_crs(get_process_graph_with_args):
159159
]
160160

161161

162+
def test_string_validation(get_process_graph_with_args):
163+
'''
164+
During the pydantic 2 update, we found that some special strings get parsed
165+
to non-string values ('t' to True, 'f' to False, etc.)
166+
167+
Check that every incoming string stays a string by default
168+
'''
169+
170+
test_args = {
171+
'arg_t': 't',
172+
'arg_f': 'f',
173+
'arg_str': 'arg_123_str',
174+
'arg_int': '123',
175+
'arg_float': '123.4',
176+
}
177+
178+
pg = get_process_graph_with_args(test_args)
179+
180+
# Parse indirectly to check if model validation is strict and does not type coerce
181+
parsed_graph = OpenEOProcessGraph(pg_data=pg)
182+
183+
# Parse directly to check if strict model validation works seperately
184+
parsed_args = [
185+
ProcessGraph.model_validate(pg, strict=True)
186+
.process_graph[TEST_NODE_KEY]
187+
.arguments[arg_name]
188+
for arg_name in test_args.keys()
189+
]
190+
191+
resolved_kwargs = parsed_graph.nodes[0][1]['resolved_kwargs'].items()
192+
193+
assert all([isinstance(resolved_kwarg, str) for _, resolved_kwarg in resolved_kwargs])
194+
195+
assert all([isinstance(parsed_arg, str) for parsed_arg in parsed_args])
196+
197+
162198
def test_bounding_box_int_crs(get_process_graph_with_args):
163199
pg = get_process_graph_with_args(
164200
{'spatial_extent': {'west': 0, 'east': 10, 'south': 0, 'north': 10, 'crs': 4326}}

0 commit comments

Comments
 (0)