Skip to content

Commit 50e7109

Browse files
authored
Fix: Fixed same level from_node resolving (#84)
1 parent fd9fb55 commit 50e7109

File tree

7 files changed

+309
-3
lines changed

7 files changed

+309
-3
lines changed

openeo_pg_parser_networkx/resolving_utils.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ def _fill_in_processes(
185185
_remap_names(
186186
process_graph=process_graph, process_replacement_id=process_replacement_id
187187
)
188+
188189
_adjust_parameters(
189190
process_graph=process_graph,
190191
process_replacement_id=process_replacement_id,
@@ -213,6 +214,13 @@ def _remap_names(process_graph, process_replacement_id):
213214
process_replacement_id
214215
].pop(old_key)
215216

217+
for _, node in process_graph[process_replacement_id].items():
218+
for _, value in node['arguments'].items():
219+
if isinstance(value, dict) and 'from_node' in value.keys():
220+
value['from_node'] = next(
221+
(t for t in name_remapping if t[1] == value['from_node']), None
222+
)[0]
223+
216224

217225
def _adjust_parameters(process_graph, process_replacement_id, arguments):
218226
'''

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.1.1"
3+
version = "2024.3.1"
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]>"]

resolved_gfm_graph.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"GFM_load1": {"process_id": "load_collection", "arguments": {"id": "GFM", "spatial_extent": {"west": 65.27044369351682, "east": 69.21281566288451, "south": 28.076233929760804, "north": 29.369117066086332}, "temporal_extent": ["2022-08-01T00:00:00Z", "2022-10-01T00:00:00Z"], "properties": {}}}, "GFM_reduce1": {"process_id": "reduce_dimension", "arguments": {"data": {"from_node": "GFM_load1"}, "reducer": {"process_graph": {"sum1": {"process_id": "sum", "arguments": {"data": {"from_parameter": "data"}}, "result": true}}}, "dimension": "time"}}, "GFM_save2": {"process_id": "save_result", "arguments": {"format": "GTIFF", "data": {"from_node": "GFM_reduce1"}}, "result": true}}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{
2+
"GFM_load1": {
3+
"process_id": "load_collection",
4+
"arguments": {
5+
"id": "GFM",
6+
"spatial_extent": {
7+
"west": 65.27044369351682,
8+
"east": 69.21281566288451,
9+
"south": 28.076233929760804,
10+
"north": 29.369117066086332
11+
},
12+
"temporal_extent": [
13+
"2022-08-01T00:00:00Z",
14+
"2022-10-01T00:00:00Z"
15+
],
16+
"properties": {}
17+
}
18+
},
19+
"GFM_reduce1": {
20+
"process_id": "reduce_dimension",
21+
"arguments": {
22+
"data": {
23+
"from_node": "GFM_load1"
24+
},
25+
"reducer": {
26+
"process_graph": {
27+
"sum1": {
28+
"process_id": "sum",
29+
"arguments": {
30+
"data": {
31+
"from_parameter": "data"
32+
}
33+
},
34+
"result": true
35+
}
36+
}
37+
},
38+
"dimension": "time"
39+
}
40+
},
41+
"GFM_save2": {
42+
"process_id": "save_result",
43+
"arguments": {
44+
"format": "GTIFF",
45+
"data": {
46+
"from_node": "GFM_reduce1"
47+
}
48+
},
49+
"result": true
50+
}
51+
}

tests/data/res_tests/udps/gfm.json

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
{
2+
"id": "GFM",
3+
"parameters": [
4+
{
5+
"schema": {
6+
"type": "array",
7+
"subtype": "temporal-interval",
8+
"title": "Single temporal interval",
9+
"description": "Left-closed temporal interval, represented as two-element array with the following elements:\n\n1. The first element is the start of the temporal interval. The specified instance in time is **included** in the interval.\n2. The second element is the end of the temporal interval. The specified instance in time is **excluded** from the interval.\n\nThe specified temporal strings follow [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339.html). Although [RFC 3339 prohibits the hour to be '24'](https://www.rfc-editor.org/rfc/rfc3339.html#section-5.7), **this process allows the value '24' for the hour** of an end time in order to make it possible that left-closed time intervals can fully cover the day. `null` can be used to specify open intervals.",
10+
"minItems": 2,
11+
"maxItems": 2,
12+
"items": {
13+
"description": "Processes and implementations may choose to only implement a subset of the subtypes specified here. Clients must check what back-ends / processes actually support.",
14+
"anyOf": [
15+
{
16+
"type": "string",
17+
"subtype": "date-time",
18+
"format": "date-time",
19+
"title": "Date with Time",
20+
"description": "Date and time representation, as defined for `date-time` by [RFC 3339 in section 5.6](https://www.rfc-editor.org/rfc/rfc3339.html#section-5.6)."
21+
},
22+
{
23+
"type": "string",
24+
"subtype": "date",
25+
"format": "date",
26+
"title": "Date only",
27+
"description": "Date only representation, as defined for `full-date` by [RFC 3339 in section 5.6](https://www.rfc-editor.org/rfc/rfc3339.html#section-5.6). The time zone is UTC."
28+
},
29+
{
30+
"type": "string",
31+
"subtype": "time",
32+
"format": "time",
33+
"title": "Time only",
34+
"description": "Time only representation, as defined for `full-time` by [RFC 3339 in section 5.6](https://www.rfc-editor.org/rfc/rfc3339.html#section-5.6). Although [RFC 3339 prohibits the hour to be '24'](https://www.rfc-editor.org/rfc/rfc3339.html#section-5.7), this definition allows the value '24' for the hour as end time in an interval in order to make it possible that left-closed time intervals can fully cover the day."
35+
},
36+
{
37+
"type": "string",
38+
"subtype": "year",
39+
"minLength": 4,
40+
"maxLength": 4,
41+
"pattern": "^\\d{4}$",
42+
"title": "Year only",
43+
"description": "Year representation, as defined for `date-fullyear` by [RFC 3339 in section 5.6](https://www.rfc-editor.org/rfc/rfc3339.html#section-5.6)."
44+
},
45+
{
46+
"type": "null"
47+
}
48+
]
49+
},
50+
"examples": [
51+
[
52+
"2015-01-01T00:00:00Z",
53+
"2016-01-01T00:00:00Z"
54+
],
55+
[
56+
"2015-01-01",
57+
"2016-01-01"
58+
],
59+
[
60+
"00:00:00Z",
61+
"12:00:00Z"
62+
],
63+
[
64+
"2015-01-01",
65+
null
66+
]
67+
]
68+
},
69+
"name": "temporal",
70+
"description": "Scrediption"
71+
},
72+
{
73+
"schema": {
74+
"type": "object",
75+
"subtype": "bounding-box",
76+
"title": "Bounding Box",
77+
"description": "A bounding box with the required fields `west`, `south`, `east`, `north` and optionally `base`, `height`, `crs`. The `crs` is a EPSG code, a WKT2:2018 string or a PROJ definition (deprecated).",
78+
"required": [
79+
"west",
80+
"south",
81+
"east",
82+
"north"
83+
],
84+
"properties": {
85+
"west": {
86+
"description": "West (lower left corner, coordinate axis 1).",
87+
"type": "number"
88+
},
89+
"south": {
90+
"description": "South (lower left corner, coordinate axis 2).",
91+
"type": "number"
92+
},
93+
"east": {
94+
"description": "East (upper right corner, coordinate axis 1).",
95+
"type": "number"
96+
},
97+
"north": {
98+
"description": "North (upper right corner, coordinate axis 2).",
99+
"type": "number"
100+
},
101+
"base": {
102+
"description": "Base (optional, lower left corner, coordinate axis 3).",
103+
"type": [
104+
"number",
105+
"null"
106+
]
107+
},
108+
"height": {
109+
"description": "Height (optional, upper right corner, coordinate axis 3).",
110+
"type": [
111+
"number",
112+
"null"
113+
]
114+
},
115+
"crs": {
116+
"description": "Coordinate reference system of the extent, specified as as [EPSG code](http://www.epsg-registry.org/), [WKT2 (ISO 19162) string](http://docs.opengeospatial.org/is/18-010r7/18-010r7.html) or [PROJ definition (deprecated)](https://proj.org/usage/quickstart.html). Defaults to `4326` (EPSG code 4326) unless the client explicitly requests a different coordinate reference system.",
117+
"anyOf": [
118+
{
119+
"type": "integer",
120+
"subtype": "epsg-code",
121+
"title": "EPSG Code",
122+
"description": "Specifies details about cartographic projections as [EPSG](http://www.epsg.org) code.",
123+
"minimum": 1000,
124+
"examples": [
125+
3857
126+
]
127+
},
128+
{
129+
"type": "string",
130+
"subtype": "wkt2-definition",
131+
"title": "WKT2 definition",
132+
"description": "Specifies details about cartographic projections as WKT2 string. Refers to the latest WKT2 version (currently [WKT2:2018](http://docs.opengeospatial.org/is/18-010r7/18-010r7.html) / ISO 19162:2018) unless otherwise stated by the process."
133+
},
134+
{
135+
"type": "string",
136+
"subtype": "proj-definition",
137+
"title": "PROJ definition",
138+
"description": "**DEPRECATED.** Specifies details about cartographic projections as [PROJ](https://proj.org/usage/quickstart.html) definition."
139+
}
140+
],
141+
"default": 4326
142+
}
143+
}
144+
},
145+
"name": "spatial",
146+
"description": "epatial sxtant"
147+
}
148+
],
149+
"process_graph": {
150+
"load1": {
151+
"process_id": "load_collection",
152+
"arguments": {
153+
"id": "GFM",
154+
"spatial_extent": {
155+
"from_parameter": "spatial"
156+
},
157+
"temporal_extent": {
158+
"from_parameter": "temporal"
159+
},
160+
"properties": {}
161+
}
162+
},
163+
"reduce1": {
164+
"process_id": "reduce_dimension",
165+
"arguments": {
166+
"data": {
167+
"from_node": "load1"
168+
},
169+
"reducer": {
170+
"process_graph": {
171+
"sum1": {
172+
"process_id": "sum",
173+
"arguments": {
174+
"data": {
175+
"from_parameter": "data"
176+
}
177+
},
178+
"result": true
179+
}
180+
}
181+
},
182+
"dimension": "time"
183+
}
184+
},
185+
"save2": {
186+
"process_id": "save_result",
187+
"arguments": {
188+
"format": "GTIFF",
189+
"data": {
190+
"from_node": "reduce1"
191+
}
192+
},
193+
"result": true
194+
}
195+
}
196+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"GFM": {
3+
"process_id": "GFM",
4+
"arguments": {
5+
"temporal": [
6+
"2022-08-01T00:00:00Z",
7+
"2022-10-01T00:00:00Z"
8+
],
9+
"spatial": {
10+
"west": 65.27044369351682,
11+
"east": 69.21281566288451,
12+
"south": 28.076233929760804,
13+
"north": 29.369117066086332
14+
}
15+
},
16+
"result": true,
17+
"namespace": "user"
18+
}
19+
}

tests/test_pg_resolving.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88

99
def get_udp(process_id: str, namespace: str) -> dict:
10+
process_id = process_id.lower()
1011
with open(f'tests/data/res_tests/udps/{process_id}.json') as f:
1112
return dict(json.load(f))
1213

@@ -23,6 +24,8 @@ def get_predefined_process_registry():
2324
('apply', {}),
2425
('load_collection', {}),
2526
('save_result', {}),
27+
('sum', {}),
28+
('reduce_dimension', {}),
2629
]
2730

2831
for process_id, spec in predefined_processes_specs:
@@ -34,7 +37,7 @@ def get_predefined_process_registry():
3437
def get_full_process_registry() -> ProcessRegistry:
3538
full_process_registry = get_predefined_process_registry()
3639

37-
for udp in ['w_add', 'valid_load', 'nested_add']:
40+
for udp in ['w_add', 'valid_load', 'nested_add', 'gfm']:
3841
full_process_registry['user', udp] = Process(
3942
get_udp(udp, "user"), implementation=None, namespace="user"
4043
)
@@ -58,13 +61,25 @@ def unresolved_pg() -> dict:
5861
return dict(json.loads(f.read()))
5962

6063

64+
@pytest.fixture
65+
def unresolved_gfm_pg() -> dict:
66+
with open('tests/data/res_tests/unresolved/unresolved_gfm.json') as f:
67+
return dict(json.loads(f.read()))
68+
69+
6170
@pytest.fixture
6271
def correctly_resolved_pg() -> dict:
6372
with open('tests/data/res_tests/resolved/resolved_complex.json') as f:
6473
return dict(json.loads(f.read()))
6574

6675

67-
def test_resolve_graph_withpredefined_process_registr(
76+
@pytest.fixture
77+
def correctly_resolved_gfm_pg() -> dict:
78+
with open('tests/data/res_tests/resolved/resolved_gfm.json') as f:
79+
return dict(json.loads(f.read()))
80+
81+
82+
def test_resolve_graph_with_predefined_process_registry(
6883
predefined_process_registry: ProcessRegistry,
6984
unresolved_pg: dict,
7085
correctly_resolved_pg: dict,
@@ -132,3 +147,19 @@ def test_resolve_graph_with_none_get_udp_spec(
132147
process_registry=predefined_process_registry,
133148
get_udp_spec=lambda x, y: None,
134149
)
150+
151+
152+
def test_resolve_gfm_graph_with_predefined_process_registry(
153+
predefined_process_registry: ProcessRegistry,
154+
unresolved_gfm_pg: dict,
155+
correctly_resolved_gfm_pg: dict,
156+
):
157+
resolved_pg = resolving_utils.resolve_process_graph(
158+
process_graph=unresolved_gfm_pg,
159+
process_registry=predefined_process_registry,
160+
get_udp_spec=get_udp,
161+
)
162+
163+
with open('resolved_gfm_graph.json', 'w') as f:
164+
json.dump(resolved_pg, f)
165+
assert correctly_resolved_gfm_pg == resolved_pg

0 commit comments

Comments
 (0)