flowrep 0.5.1__tar.gz → 0.5.2__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.
- {flowrep-0.5.1 → flowrep-0.5.2}/PKG-INFO +1 -1
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/_version.py +2 -2
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/parsers/atomic_parser.py +13 -7
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/retrospective/datastructures.py +26 -5
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/retrospective/storage.py +12 -3
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/wfms.py +10 -14
- {flowrep-0.5.1 → flowrep-0.5.2}/.gitignore +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/LICENSE +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/docs/README.md +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/pyproject.toml +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/__init__.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/api/__init__.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/api/schemas.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/api/tools.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/base_models.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/compiler/__init__.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/compiler/annotate.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/compiler/flow_control.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/compiler/function.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/compiler/source.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/compiler/statements.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/converters/__init__.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/converters/python_workflow_definition.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/edge_models.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/parsers/__init__.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/parsers/case_helpers.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/parsers/for_parser.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/parsers/if_parser.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/parsers/label_helpers.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/parsers/object_scope.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/parsers/parser_helpers.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/parsers/parser_protocol.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/parsers/symbol_scope.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/parsers/try_parser.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/parsers/while_parser.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/parsers/workflow_parser.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/prospective/__init__.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/prospective/atomic_recipe.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/prospective/for_recipe.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/prospective/helper_models.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/prospective/if_recipe.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/prospective/try_recipe.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/prospective/union_types.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/prospective/while_recipe.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/prospective/workflow_recipe.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/retrospective/__init__.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/retrospective/storage_widget.py +0 -0
- {flowrep-0.5.1 → flowrep-0.5.2}/src/flowrep/subgraph_validation.py +0 -0
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.5.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 5,
|
|
21
|
+
__version__ = version = '0.5.2'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 5, 2)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -241,19 +241,25 @@ def _parse_dataclass_return_labels(func: FunctionType) -> list[str]:
|
|
|
241
241
|
f"{source_code_return}"
|
|
242
242
|
)
|
|
243
243
|
|
|
244
|
-
|
|
245
|
-
|
|
244
|
+
try:
|
|
245
|
+
hints = get_type_hints(func, include_extras=True)
|
|
246
|
+
except NameError as e:
|
|
247
|
+
raise NameError(
|
|
248
|
+
"Dataclass unpack mode requires the return annotation to be importable at "
|
|
249
|
+
"runtime. Evaluating the return annotation for "
|
|
250
|
+
f"{func.__module__}.{func.__qualname__} failed with: {e}"
|
|
251
|
+
) from e
|
|
252
|
+
ann = hints.get("return")
|
|
246
253
|
|
|
247
|
-
# unwrap Annotated
|
|
248
254
|
origin = get_origin(ann)
|
|
249
|
-
|
|
255
|
+
return_hint = get_args(ann)[0] if origin is Annotated else ann
|
|
250
256
|
|
|
251
|
-
if dataclasses.is_dataclass(
|
|
252
|
-
return [f.name for f in dataclasses.fields(
|
|
257
|
+
if dataclasses.is_dataclass(return_hint):
|
|
258
|
+
return [f.name for f in dataclasses.fields(return_hint)]
|
|
253
259
|
|
|
254
260
|
raise ValueError(
|
|
255
261
|
f"Dataclass unpack mode requires a return type annotation that is a "
|
|
256
|
-
f"(perhaps Annotated) dataclass, but got {
|
|
262
|
+
f"(perhaps Annotated) dataclass, but got {return_hint}"
|
|
257
263
|
)
|
|
258
264
|
|
|
259
265
|
|
|
@@ -239,7 +239,16 @@ def _parse_function(
|
|
|
239
239
|
dict[base_models.Label, OutputDataPort],
|
|
240
240
|
]:
|
|
241
241
|
function = retrieve.import_from_string(fully_qualified_name)
|
|
242
|
-
|
|
242
|
+
try:
|
|
243
|
+
hints = get_type_hints(function, include_extras=True)
|
|
244
|
+
except NameError as e:
|
|
245
|
+
raise NameError(
|
|
246
|
+
f"While parsing {fully_qualified_name!r} for recipe inputs {inputs} and "
|
|
247
|
+
f"outputs {outputs}, could not find the symbol for at least one "
|
|
248
|
+
f"annotation. This is likely due to forward referenced annotations. Please "
|
|
249
|
+
f"cross reference the underlying name error ({str(e)!r}) and the function "
|
|
250
|
+
f"being parsed, and locally make the necessary imports before re-parsing."
|
|
251
|
+
) from e
|
|
243
252
|
sig = inspect.signature(function)
|
|
244
253
|
|
|
245
254
|
variadics_in_sig = {
|
|
@@ -342,13 +351,27 @@ def _parse_return_tuple(
|
|
|
342
351
|
def _parse_return_dataclass(
|
|
343
352
|
return_annotation, outputs: list[str]
|
|
344
353
|
) -> dict[str, OutputDataPort]:
|
|
345
|
-
if not
|
|
354
|
+
if not (
|
|
355
|
+
isinstance(return_annotation, type)
|
|
356
|
+
and dataclasses.is_dataclass(return_annotation)
|
|
357
|
+
): # pragma: no cover
|
|
346
358
|
raise TypeError(
|
|
347
359
|
f"Return annotation {return_annotation!r} is not a dataclass. This should "
|
|
348
360
|
f"have been caught by the underlying recipe validation. Please raise a "
|
|
349
361
|
f"GitHub issue reporting how you got here!"
|
|
350
362
|
)
|
|
351
363
|
|
|
364
|
+
# de-stringify dataclass annotations, if they were forward-references
|
|
365
|
+
try:
|
|
366
|
+
hints = get_type_hints(return_annotation, include_extras=True)
|
|
367
|
+
except NameError as e:
|
|
368
|
+
fqdn = f"{return_annotation.__module__}.{return_annotation.__qualname__}"
|
|
369
|
+
raise NameError(
|
|
370
|
+
f"While parsing return dataclass annotation {fqdn!r}, could not resolve "
|
|
371
|
+
f"at least one field annotation ({e}). Ensure the missing symbols are "
|
|
372
|
+
f"importable at runtime in the dataclass' defining module."
|
|
373
|
+
) from e
|
|
374
|
+
|
|
352
375
|
fields = dataclasses.fields(return_annotation)
|
|
353
376
|
if len(outputs) != len(fields): # pragma: no cover
|
|
354
377
|
raise ValueError(
|
|
@@ -359,8 +382,6 @@ def _parse_return_dataclass(
|
|
|
359
382
|
)
|
|
360
383
|
|
|
361
384
|
return {
|
|
362
|
-
label: OutputDataPort(
|
|
363
|
-
annotation=(field.type if field.type is not dataclasses.MISSING else None),
|
|
364
|
-
)
|
|
385
|
+
label: OutputDataPort(annotation=hints.get(field.name, None))
|
|
365
386
|
for label, field in zip(outputs, fields, strict=True)
|
|
366
387
|
}
|
|
@@ -62,9 +62,12 @@ class LexicalBagBrowser:
|
|
|
62
62
|
) -> (
|
|
63
63
|
datastructures.AtomicData
|
|
64
64
|
| datastructures.DagData
|
|
65
|
-
| datastructures.
|
|
65
|
+
| datastructures.ForEachData
|
|
66
|
+
| datastructures.IfData
|
|
66
67
|
| datastructures.InputDataPort
|
|
67
68
|
| datastructures.OutputDataPort
|
|
69
|
+
| datastructures.TryData
|
|
70
|
+
| datastructures.WhileData
|
|
68
71
|
):
|
|
69
72
|
"""Load a node or IO port using its lexical path."""
|
|
70
73
|
return load_from_bag(self.bag, path)
|
|
@@ -164,9 +167,12 @@ def load_from_bag(
|
|
|
164
167
|
) -> (
|
|
165
168
|
datastructures.AtomicData
|
|
166
169
|
| datastructures.DagData
|
|
167
|
-
| datastructures.
|
|
170
|
+
| datastructures.ForEachData
|
|
171
|
+
| datastructures.IfData
|
|
168
172
|
| datastructures.InputDataPort
|
|
169
173
|
| datastructures.OutputDataPort
|
|
174
|
+
| datastructures.TryData
|
|
175
|
+
| datastructures.WhileData
|
|
170
176
|
):
|
|
171
177
|
"""
|
|
172
178
|
Load data from a :cls:`LiveNode` stored in a *bagofholding* by using its lexical
|
|
@@ -205,9 +211,12 @@ def load_from_bag(
|
|
|
205
211
|
expected_types = (
|
|
206
212
|
datastructures.AtomicData,
|
|
207
213
|
datastructures.DagData,
|
|
208
|
-
datastructures.
|
|
214
|
+
datastructures.ForEachData,
|
|
215
|
+
datastructures.IfData,
|
|
209
216
|
datastructures.InputDataPort,
|
|
210
217
|
datastructures.OutputDataPort,
|
|
218
|
+
datastructures.TryData,
|
|
219
|
+
datastructures.WhileData,
|
|
211
220
|
)
|
|
212
221
|
if not isinstance(obj, expected_types):
|
|
213
222
|
raise TypeError(
|
|
@@ -207,7 +207,7 @@ def _populate_workflow_outputs(
|
|
|
207
207
|
|
|
208
208
|
def _run_for(
|
|
209
209
|
recipe: for_recipe.ForEachRecipe, **kwargs: Any
|
|
210
|
-
) -> datastructures.
|
|
210
|
+
) -> datastructures.ForEachData:
|
|
211
211
|
"""
|
|
212
212
|
Execute a for-node by scattering iterated inputs across body instances and
|
|
213
213
|
collecting outputs into lists.
|
|
@@ -217,7 +217,7 @@ def _run_for(
|
|
|
217
217
|
Transferred outputs collect the per-iteration value of a scattered input,
|
|
218
218
|
preserving the link between input element and body output element.
|
|
219
219
|
"""
|
|
220
|
-
node = datastructures.
|
|
220
|
+
node = datastructures.ForEachData.from_recipe(recipe)
|
|
221
221
|
_populate_input_ports(node, kwargs)
|
|
222
222
|
|
|
223
223
|
body_label = recipe.body_node.label
|
|
@@ -298,7 +298,7 @@ def _run_for(
|
|
|
298
298
|
|
|
299
299
|
def _run_while(
|
|
300
300
|
recipe: while_recipe.WhileRecipe, **kwargs: Any
|
|
301
|
-
) -> datastructures.
|
|
301
|
+
) -> datastructures.WhileData:
|
|
302
302
|
"""
|
|
303
303
|
Execute a while-node by repeatedly evaluating a condition and running a body.
|
|
304
304
|
|
|
@@ -306,7 +306,7 @@ def _run_while(
|
|
|
306
306
|
feed back into the next condition/body evaluation. If the condition is false on
|
|
307
307
|
the first check, outputs are sourced from the initial input values.
|
|
308
308
|
"""
|
|
309
|
-
node = datastructures.
|
|
309
|
+
node = datastructures.WhileData.from_recipe(recipe)
|
|
310
310
|
_populate_input_ports(node, kwargs)
|
|
311
311
|
|
|
312
312
|
cond_label = recipe.case.condition.label
|
|
@@ -355,16 +355,14 @@ def _run_while(
|
|
|
355
355
|
# ---------------------------------------------------------------------------
|
|
356
356
|
|
|
357
357
|
|
|
358
|
-
def _run_if(
|
|
359
|
-
recipe: if_recipe.IfRecipe, **kwargs: Any
|
|
360
|
-
) -> datastructures.FlowControlData:
|
|
358
|
+
def _run_if(recipe: if_recipe.IfRecipe, **kwargs: Any) -> datastructures.IfData:
|
|
361
359
|
"""
|
|
362
360
|
Execute an if-node by walking cases until a condition evaluates positively,
|
|
363
361
|
then executing the matching body (or the else case).
|
|
364
362
|
|
|
365
363
|
Output ports that have no source from the executed branch remain NOT_DATA.
|
|
366
364
|
"""
|
|
367
|
-
node = datastructures.
|
|
365
|
+
node = datastructures.IfData.from_recipe(recipe)
|
|
368
366
|
_populate_input_ports(node, kwargs)
|
|
369
367
|
|
|
370
368
|
for case in recipe.cases:
|
|
@@ -387,7 +385,7 @@ def _run_if(
|
|
|
387
385
|
|
|
388
386
|
|
|
389
387
|
def _execute_if_branch(
|
|
390
|
-
node: datastructures.
|
|
388
|
+
node: datastructures.IfData,
|
|
391
389
|
recipe: if_recipe.IfRecipe,
|
|
392
390
|
branch: helper_models.LabeledRecipe,
|
|
393
391
|
) -> None:
|
|
@@ -403,14 +401,12 @@ def _execute_if_branch(
|
|
|
403
401
|
# ---------------------------------------------------------------------------
|
|
404
402
|
|
|
405
403
|
|
|
406
|
-
def _run_try(
|
|
407
|
-
recipe: try_recipe.TryRecipe, **kwargs: Any
|
|
408
|
-
) -> datastructures.FlowControlData:
|
|
404
|
+
def _run_try(recipe: try_recipe.TryRecipe, **kwargs: Any) -> datastructures.TryData:
|
|
409
405
|
"""
|
|
410
406
|
Execute a try-node: run the try body and, on exception, walk exception cases
|
|
411
407
|
for a matching handler. If no handler matches, the exception propagates.
|
|
412
408
|
"""
|
|
413
|
-
node = datastructures.
|
|
409
|
+
node = datastructures.TryData.from_recipe(recipe)
|
|
414
410
|
_populate_input_ports(node, kwargs)
|
|
415
411
|
|
|
416
412
|
try_kwargs = _gather_dynamic_child_inputs(
|
|
@@ -493,7 +489,7 @@ def _evaluate_condition(
|
|
|
493
489
|
|
|
494
490
|
|
|
495
491
|
def _populate_prospective_outputs(
|
|
496
|
-
node: datastructures.
|
|
492
|
+
node: datastructures.IfData | datastructures.TryData,
|
|
497
493
|
prospective_output_edges: dict[
|
|
498
494
|
edge_models.OutputTarget, list[edge_models.SourceHandle]
|
|
499
495
|
],
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|