From 0962846536b9a9c8c35985be27164578245d3c13 Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Mon, 27 Jul 2026 06:53:30 +0200 Subject: [PATCH 01/19] Configure Ruff for linting in pyproject.toml Add Ruff configuration for linting with specified rules. --- pyproject.toml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index c06709a..ba8cf98 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,6 +42,32 @@ plot = [ "ipython>=7.33.0,<=9.8.0", ] +[tool.ruff] +exclude = [".ci_support", "docs", "notebooks", "tests", "setup.py", "_version.py"] + +[tool.ruff.lint] +select = [ + # pycodestyle + "E", + # Pyflakes + "F", + # pyupgrade + "UP", + # flake8-bugbear + "B", + # flake8-simplify + "SIM", + # isort + "I", + # flake8-comprehensions + "C4", + # eradicate + "ERA", + # pylint + "PL", +] +ignore = [] + [tool.hatch.build] include = [ "src/python_workflow_definition" From 32bf515c5b75d5a5c4a4786e52dcb56100c18245 Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Mon, 27 Jul 2026 06:54:25 +0200 Subject: [PATCH 02/19] Add ruff pre-commit hooks for linting and formatting --- .pre-commit-config.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..422cfca --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,10 @@ +repos: + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.15.22 + hooks: + - id: ruff + name: ruff lint + args: ["--fix"] + files: ^src/python_workflow_definition/ + - id: ruff-format + name: ruff format From 6eae8e183df64e4a6c1d6c2f625cd372234059de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 27 Jul 2026 07:00:37 +0200 Subject: [PATCH 03/19] do not apply on notebooks for now --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ba8cf98..ba59460 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ plot = [ ] [tool.ruff] -exclude = [".ci_support", "docs", "notebooks", "tests", "setup.py", "_version.py"] +exclude = ["documentation", "example_workflows", "tests", "binder", "_version.py"] [tool.ruff.lint] select = [ From dd8354094fbbda6a5e822c852d0bbd8829f7cf3f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 27 Jul 2026 05:01:04 +0000 Subject: [PATCH 04/19] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/python_workflow_definition/aiida.py | 1 - .../cwl/__init__.py | 59 +++++++++---------- src/python_workflow_definition/executorlib.py | 8 +-- src/python_workflow_definition/jobflow.py | 16 +++-- src/python_workflow_definition/models.py | 40 ++++++------- src/python_workflow_definition/plot.py | 1 - src/python_workflow_definition/purepython.py | 14 ++--- src/python_workflow_definition/pyiron_base.py | 20 +++---- .../pyiron_workflow.py | 42 +++++-------- src/python_workflow_definition/shared.py | 4 +- 10 files changed, 88 insertions(+), 117 deletions(-) diff --git a/src/python_workflow_definition/aiida.py b/src/python_workflow_definition/aiida.py index 30212b3..9d17dc0 100644 --- a/src/python_workflow_definition/aiida.py +++ b/src/python_workflow_definition/aiida.py @@ -99,7 +99,6 @@ def write_workflow_json(wg: WorkGraph, file_name: str) -> None: GRAPH_LEVEL_NAMES = ["graph_inputs", "graph_outputs", "graph_ctx"] for node in wg.tasks: - if node.name in GRAPH_LEVEL_NAMES: continue diff --git a/src/python_workflow_definition/cwl/__init__.py b/src/python_workflow_definition/cwl/__init__.py index 05885fc..96ae76e 100644 --- a/src/python_workflow_definition/cwl/__init__.py +++ b/src/python_workflow_definition/cwl/__init__.py @@ -21,8 +21,7 @@ def _get_function_argument(argument: str, position: int = 3) -> dict: return { - argument - + "_file": { + argument + "_file": { "type": "File", "inputBinding": { "prefix": "--arg_" + argument + "=", @@ -45,8 +44,10 @@ def _get_function_template(function_name: str) -> dict: def _get_output_name(output_name: str) -> dict: return { - output_name - + "_file": {"type": "File", "outputBinding": {"glob": output_name + ".pickle"}} + output_name + "_file": { + "type": "File", + "outputBinding": {"glob": output_name + ".pickle"}, + } } @@ -55,7 +56,7 @@ def _get_function(workflow): n["id"]: n["value"] for n in workflow[NODES_LABEL] if n["type"] == "function" } funct_dict = {} - for funct_id in function_nodes_dict.keys(): + for funct_id in function_nodes_dict: target_ports = list( set( [ @@ -142,10 +143,7 @@ def _write_workflow_config(workflow, directory_path: str = "."): export_path.mkdir(parents=True, exist_ok=True) with open(export_path / "workflow.yml", "w") as f: dump( - { - k + "_file": {"class": "File", "path": k + ".pickle"} - for k in input_dict.keys() - }, + {k + "_file": {"class": "File", "path": k + ".pickle"} for k in input_dict}, f, Dumper=Dumper, ) @@ -170,7 +168,7 @@ def _write_workflow(workflow, directory_path: str = "."): last_compute_id = [ e[SOURCE_LABEL] for e in workflow[EDGES_LABEL] if e[TARGET_LABEL] == result_id ][0] - workflow_template["inputs"].update({k + "_file": "File" for k in input_dict.keys()}) + workflow_template["inputs"].update({k + "_file": "File" for k in input_dict}) if funct_dict[last_compute_id]["sourcePorts"] == [None]: workflow_template["outputs"] = { "result_file": { @@ -209,28 +207,29 @@ def _write_workflow(workflow, directory_path: str = "."): for k, v in t[1].items(): if v[SOURCE_LABEL] in input_id_dict: in_dict[k + "_file"] = input_id_dict[v[SOURCE_LABEL]] + "_file" + elif v["sourcePort"] is None: + in_dict[k + "_file"] = ( + step_name_lst[v[SOURCE_LABEL]] + + "_" + + str(v[SOURCE_LABEL]) + + "/result_file" + ) else: - if v["sourcePort"] is None: - in_dict[k + "_file"] = ( - step_name_lst[v[SOURCE_LABEL]] - + "_" - + str(v[SOURCE_LABEL]) - + "/result_file" - ) - else: - in_dict[k + "_file"] = ( - step_name_lst[v[SOURCE_LABEL]] - + "_" - + str(v[SOURCE_LABEL]) - + "/" - + v[SOURCE_PORT_LABEL] - + "_file" - ) + in_dict[k + "_file"] = ( + step_name_lst[v[SOURCE_LABEL]] + + "_" + + str(v[SOURCE_LABEL]) + + "/" + + v[SOURCE_PORT_LABEL] + + "_file" + ) workflow_template["steps"].update( { - step_name_lst[ind] - + "_" - + str(ind): {"run": node_script, "in": in_dict, "out": output} + step_name_lst[ind] + "_" + str(ind): { + "run": node_script, + "in": in_dict, + "out": output, + } } ) export_path = Path(directory_path) @@ -240,7 +239,7 @@ def _write_workflow(workflow, directory_path: str = "."): def write_workflow(file_name: str, directory_path: str = "."): - with open(file_name, "r") as f: + with open(file_name) as f: workflow = json.load(f) _write_function_cwl(workflow=workflow, directory_path=directory_path) diff --git a/src/python_workflow_definition/executorlib.py b/src/python_workflow_definition/executorlib.py index 552d44b..8cb76cb 100644 --- a/src/python_workflow_definition/executorlib.py +++ b/src/python_workflow_definition/executorlib.py @@ -11,10 +11,6 @@ SOURCE_LABEL, SOURCE_PORT_LABEL, convert_nodes_list_to_dict, - get_dict, - get_kwargs, - get_list, - get_source_handles, remove_result, ) @@ -25,9 +21,9 @@ def get_item(obj, key): def _get_value(result_dict: dict, nodes_new_dict: dict, link_dict: dict, exe: Executor): source, source_handle = link_dict[SOURCE_LABEL], link_dict[SOURCE_PORT_LABEL] - if source in result_dict.keys(): + if source in result_dict: result = result_dict[source] - elif source in nodes_new_dict.keys(): + elif source in nodes_new_dict: result = nodes_new_dict[source] else: raise KeyError() diff --git a/src/python_workflow_definition/jobflow.py b/src/python_workflow_definition/jobflow.py index b385177..348c446 100644 --- a/src/python_workflow_definition/jobflow.py +++ b/src/python_workflow_definition/jobflow.py @@ -196,10 +196,8 @@ def _get_edges_and_extend_nodes( def _resort_total_lst(total_dict: dict, nodes_dict: dict) -> dict: - nodes_with_dep_lst = list(sorted(total_dict.keys())) - nodes_without_dep_lst = [ - k for k in nodes_dict.keys() if k not in nodes_with_dep_lst - ] + nodes_with_dep_lst = sorted(total_dict.keys()) + nodes_without_dep_lst = [k for k in nodes_dict if k not in nodes_with_dep_lst] ordered_lst: list = [] total_new_dict: dict[Any, dict] = {} while len(total_new_dict) < len(total_dict): @@ -220,7 +218,7 @@ def _group_edges(edges_lst: list) -> dict: for ed_major in edges_lst: target_id = ed_major[TARGET_LABEL] tmp_lst = [] - if target_id not in total_dict.keys(): + if target_id not in total_dict: for ed in edges_lst: if target_id == ed[TARGET_LABEL]: tmp_lst.append(ed) @@ -237,15 +235,15 @@ def _get_workflow( ) -> list: def get_attr_helper(obj, source_handle): if source_handle is None: - return getattr(obj, "output") + return obj.output else: - return getattr(getattr(obj, "output"), source_handle) + return getattr(obj.output, source_handle) memory_dict: dict[Any, Any] = {} - for k in total_dict.keys(): + for k in total_dict: v = nodes_dict[k] if isfunction(v): - if k in source_handles_dict.keys(): + if k in source_handles_dict: fn = job( method=v, data=[el for el in source_handles_dict[k] if el is not None], diff --git a/src/python_workflow_definition/models.py b/src/python_workflow_definition/models.py index 6ddb583..8265132 100644 --- a/src/python_workflow_definition/models.py +++ b/src/python_workflow_definition/models.py @@ -1,7 +1,7 @@ import json import logging from pathlib import Path -from typing import Annotated, Any, List, Literal, Optional, Type, TypeVar, Union +from typing import Annotated, Any, Literal, TypeVar, Union from pydantic import ( BaseModel, @@ -29,7 +29,7 @@ JsonPrimitive = Union[str, int, float, bool, None] AllowableDefaults = TypeAliasType( "AllowableDefaults", - "Union[JsonPrimitive, dict[str, AllowableDefaults], list[AllowableDefaults]]", + "JsonPrimitive | dict[str, AllowableDefaults] | list[AllowableDefaults]", ) @@ -47,7 +47,7 @@ class PythonWorkflowDefinitionInputNode(PythonWorkflowDefinitionBaseNode): type: Literal["input"] name: str - value: Optional[AllowableDefaults] = None + value: AllowableDefaults | None = None class PythonWorkflowDefinitionOutputNode(PythonWorkflowDefinitionBaseNode): @@ -80,11 +80,9 @@ def check_value_format(cls, v: str): # Discriminated Union for Nodes PythonWorkflowDefinitionNode = Annotated[ - Union[ - PythonWorkflowDefinitionInputNode, - PythonWorkflowDefinitionOutputNode, - PythonWorkflowDefinitionFunctionNode, - ], + PythonWorkflowDefinitionInputNode + | PythonWorkflowDefinitionOutputNode + | PythonWorkflowDefinitionFunctionNode, Field(discriminator="type"), ] @@ -93,13 +91,13 @@ class PythonWorkflowDefinitionEdge(BaseModel): """Model for edges connecting nodes.""" target: int - targetPort: Optional[str] = None + targetPort: str | None = None source: int - sourcePort: Optional[str] = None + sourcePort: str | None = None @field_validator("sourcePort", mode="before") @classmethod - def handle_default_source(cls, v: Any) -> Optional[str]: + def handle_default_source(cls, v: Any) -> str | None: """ Transforms incoming None/null for sourcePort to INTERNAL_DEFAULT_HANDLE. Runs before standard validation. @@ -117,7 +115,7 @@ def handle_default_source(cls, v: Any) -> Optional[str]: return v @field_serializer("sourcePort") - def serialize_source_handle(self, v: Optional[str]) -> Optional[str]: + def serialize_source_handle(self, v: str | None) -> str | None: """ SERIALIZATION (Output): Converts internal INTERNAL_DEFAULT_HANDLE ("__result__") back to None. @@ -131,13 +129,13 @@ class PythonWorkflowDefinitionWorkflow(BaseModel): """The main workflow model.""" version: str - nodes: List[PythonWorkflowDefinitionNode] - edges: List[PythonWorkflowDefinitionEdge] + nodes: list[PythonWorkflowDefinitionNode] + edges: list[PythonWorkflowDefinitionEdge] def dump_json( self, *, - indent: Optional[int] = 2, + indent: int | None = 2, **kwargs, ) -> str: """ @@ -171,9 +169,9 @@ def dump_json( def dump_json_file( self, - file_name: Union[str, Path], + file_name: str | Path, *, - indent: Optional[int] = 2, + indent: int | None = 2, **kwargs, ) -> None: """ @@ -196,14 +194,14 @@ def dump_json_file( with open(file_name, "w", encoding="utf-8") as f: f.write(json_string) logger.info(f"Successfully wrote workflow model to {file_name}.") - except IOError as e: + except OSError as e: logger.error( f"Error writing workflow model to file {file_name}: {e}", exc_info=True ) raise @classmethod - def load_json_str(cls: Type[T], json_data: Union[str, bytes]) -> dict: + def load_json_str(cls: type[T], json_data: str | bytes) -> dict: """ Loads and validates workflow data from a JSON string or bytes. @@ -239,7 +237,7 @@ def load_json_str(cls: Type[T], json_data: Union[str, bytes]) -> dict: raise @classmethod - def load_json_file(cls: Type[T], file_name: Union[str, Path]) -> dict: + def load_json_file(cls: type[T], file_name: str | Path) -> dict: """ Loads and validates workflow data from a JSON file. @@ -263,6 +261,6 @@ def load_json_file(cls: Type[T], file_name: Union[str, Path]) -> dict: except FileNotFoundError: logger.error(f"JSON file not found: {file_name}", exc_info=True) raise - except IOError as e: + except OSError as e: logger.error(f"Error reading JSON file {file_name}: {e}", exc_info=True) raise diff --git a/src/python_workflow_definition/plot.py b/src/python_workflow_definition/plot.py index d0ca1b7..04d4413 100644 --- a/src/python_workflow_definition/plot.py +++ b/src/python_workflow_definition/plot.py @@ -11,7 +11,6 @@ SOURCE_LABEL, SOURCE_PORT_LABEL, convert_nodes_list_to_dict, - get_kwargs, ) diff --git a/src/python_workflow_definition/purepython.py b/src/python_workflow_definition/purepython.py index 0e77bd3..7d0407f 100644 --- a/src/python_workflow_definition/purepython.py +++ b/src/python_workflow_definition/purepython.py @@ -9,21 +9,15 @@ SOURCE_LABEL, SOURCE_PORT_LABEL, TARGET_LABEL, - TARGET_PORT_LABEL, convert_nodes_list_to_dict, - get_dict, get_kwargs, - get_list, - get_source_handles, remove_result, ) def resort_total_lst(total_lst: list, nodes_dict: dict) -> list: - nodes_with_dep_lst = list(sorted([v[0] for v in total_lst])) - nodes_without_dep_lst = [ - k for k in nodes_dict.keys() if k not in nodes_with_dep_lst - ] + nodes_with_dep_lst = sorted([v[0] for v in total_lst]) + nodes_without_dep_lst = [k for k in nodes_dict if k not in nodes_with_dep_lst] ordered_lst: list = [] total_new_lst: list[list] = [] while len(total_new_lst) < len(total_lst): @@ -55,9 +49,9 @@ def group_edges(edges_lst: list) -> list: def _get_value(result_dict: dict, nodes_new_dict: dict, link_dict: dict): source, source_handle = link_dict[SOURCE_LABEL], link_dict[SOURCE_PORT_LABEL] - if source in result_dict.keys(): + if source in result_dict: result = result_dict[source] - elif source in nodes_new_dict.keys(): + elif source in nodes_new_dict: result = nodes_new_dict[source] else: raise KeyError() diff --git a/src/python_workflow_definition/pyiron_base.py b/src/python_workflow_definition/pyiron_base.py index 17e4aaa..eb92ec9 100644 --- a/src/python_workflow_definition/pyiron_base.py +++ b/src/python_workflow_definition/pyiron_base.py @@ -1,6 +1,6 @@ from importlib import import_module from inspect import isfunction -from typing import Any, Optional +from typing import Any import numpy as np from pyiron_base import Project, job @@ -26,10 +26,8 @@ def _resort_total_lst(total_lst: list, nodes_dict: dict) -> list: - nodes_with_dep_lst = list(sorted([v[0] for v in total_lst])) - nodes_without_dep_lst = [ - k for k in nodes_dict.keys() if k not in nodes_with_dep_lst - ] + nodes_with_dep_lst = sorted([v[0] for v in total_lst]) + nodes_without_dep_lst = [k for k in nodes_dict if k not in nodes_with_dep_lst] ordered_lst: list = [] total_new_lst: list[list] = [] while len(total_new_lst) < len(total_lst): @@ -62,11 +60,11 @@ def _group_edges(edges_lst: list) -> list: def _get_source( nodes_dict: dict, delayed_object_dict: dict, source: str, source_handle: str ): - if source in delayed_object_dict.keys() and source_handle is not None: + if source in delayed_object_dict and source_handle is not None: return ( delayed_object_dict[source].__getattr__("output").__getattr__(source_handle) ) - elif source in delayed_object_dict.keys(): + elif source in delayed_object_dict: return delayed_object_dict[source] else: return nodes_dict[source] @@ -103,7 +101,7 @@ def get_list(**kwargs) -> list: def _remove_server_obj(nodes_dict: dict, edges_lst: list): - server_lst = [k for k in nodes_dict.keys() if k.startswith("_server_obj_")] + server_lst = [k for k in nodes_dict if k.startswith("_server_obj_")] for s in server_lst: del nodes_dict[s] edges_lst = [ep for ep in edges_lst if s not in ep] @@ -138,7 +136,7 @@ def _get_unique_objects(nodes_dict: dict): unique_lst: list = [] delayed_object_updated_dict: dict[Any, DelayedObject] = {} match_dict: dict[Any, Any] = {} - for dobj in delayed_object_dict.keys(): + for dobj in delayed_object_dict: match = False for obj in unique_lst: if ( @@ -180,7 +178,7 @@ def _get_connection_dict(delayed_object_updated_dict: dict, match_dict: dict): lookup_dict[i] = k for k, v in match_dict.items(): - if v in connection_dict.keys(): + if v in connection_dict: connection_dict[k] = connection_dict[v] return connection_dict, lookup_dict @@ -230,7 +228,7 @@ def _get_edges_dict( return edges_dict_lst -def load_workflow_json(file_name: str, project: Optional[Project] = None): +def load_workflow_json(file_name: str, project: Project | None = None): if project is None: project = Project(".") diff --git a/src/python_workflow_definition/pyiron_workflow.py b/src/python_workflow_definition/pyiron_workflow.py index 73d994b..33f49a3 100644 --- a/src/python_workflow_definition/pyiron_workflow.py +++ b/src/python_workflow_definition/pyiron_workflow.py @@ -4,7 +4,7 @@ from typing import Any import numpy as np -from pyiron_workflow import Workflow, as_function_node, function_node +from pyiron_workflow import Workflow, function_node from pyiron_workflow.api import Function from python_workflow_definition.models import PythonWorkflowDefinitionWorkflow @@ -111,8 +111,7 @@ def write_workflow_json(graph_as_dict: dict, file_name: str = "workflow.json"): item_node_lst = [ e[SOURCE_LABEL] for e in edges_lst - if e[TARGET_LABEL] in pyiron_workflow_modules.keys() - and e[TARGET_PORT_LABEL] == "item" + if e[TARGET_LABEL] in pyiron_workflow_modules and e[TARGET_PORT_LABEL] == "item" ] values_from_dict_lst = [ @@ -129,8 +128,8 @@ def write_workflow_json(graph_as_dict: dict, file_name: str = "workflow.json"): nodes_remaining_dict = { k: v for k, v in nodes_dict.items() - if k not in pyiron_workflow_modules.keys() - and k not in remap_dict.keys() + if k not in pyiron_workflow_modules + and k not in remap_dict and k not in item_node_lst and k not in remap_get_list_dict.values() } @@ -178,7 +177,7 @@ def write_workflow_json(graph_as_dict: dict, file_name: str = "workflow.json"): SOURCE_PORT_LABEL: connected_edge[SOURCE_PORT_LABEL], } edge_get_list_updated_lst.append(edge_updated) - elif edge[SOURCE_LABEL] in remap_dict.keys(): + elif edge[SOURCE_LABEL] in remap_dict: edge_updated = { TARGET_LABEL: edge[TARGET_LABEL], TARGET_PORT_LABEL: edge[TARGET_PORT_LABEL], @@ -191,7 +190,7 @@ def write_workflow_json(graph_as_dict: dict, file_name: str = "workflow.json"): target_dict: dict[Any, list] = {} for edge in edge_get_list_updated_lst: - for k in pyiron_workflow_modules.keys(): + for k in pyiron_workflow_modules: if k == edge[TARGET_LABEL]: if k not in target_dict: target_dict[k] = [] @@ -199,14 +198,14 @@ def write_workflow_json(graph_as_dict: dict, file_name: str = "workflow.json"): source_dict: dict[Any, list] = {} for edge in edge_get_list_updated_lst: - for k in pyiron_workflow_modules.keys(): + for k in pyiron_workflow_modules: if k == edge[SOURCE_LABEL]: if k not in source_dict: source_dict[k] = [] source_dict[k].append(edge) edge_new_lst, nodes_to_delete = [], [] - for k in target_dict.keys(): + for k in target_dict: source, sourcehandle = None, None for edge in target_dict[k]: if edge[SOURCE_PORT_LABEL] is None: @@ -214,7 +213,7 @@ def write_workflow_json(graph_as_dict: dict, file_name: str = "workflow.json"): nodes_to_delete.append(edge[SOURCE_LABEL]) else: source = edge[SOURCE_LABEL] - if "s_" == source_dict[k][-1][TARGET_PORT_LABEL][:2]: + if source_dict[k][-1][TARGET_PORT_LABEL][:2] == "s_": edge_new_lst.append( { SOURCE_LABEL: nodes_final_order_dict[source], @@ -247,16 +246,7 @@ def write_workflow_json(graph_as_dict: dict, file_name: str = "workflow.json"): if ( isfunction(source_node) and source_node.__name__ == edge[SOURCE_PORT_LABEL] - ): - edge_new_lst.append( - { - TARGET_LABEL: nodes_final_order_dict[edge[TARGET_LABEL]], - TARGET_PORT_LABEL: edge[TARGET_PORT_LABEL], - SOURCE_LABEL: nodes_final_order_dict[edge[SOURCE_LABEL]], - SOURCE_PORT_LABEL: None, - } - ) - elif ( + ) or ( isfunction(source_node) and source_node.__name__ == "get_dict" and edge[SOURCE_PORT_LABEL] == "dict" @@ -328,15 +318,15 @@ def load_workflow_json(file_name: str) -> Workflow: PythonWorkflowDefinitionWorkflow.load_json_file(file_name=file_name) ) - input_values: dict[int, object] = ( - {} - ) # Type is actually more restrictive, must be jsonifyable object + input_values: dict[ + int, object + ] = {} # Type is actually more restrictive, must be jsonifyable object nodes: dict[int, Function] = {} total_counter_dict = Counter( [n["value"] for n in content[NODES_LABEL] if n["type"] == "function"] ) - counter_dict = {k: -1 for k in total_counter_dict.keys()} - wf = Workflow(file_name.split(".")[0]) + counter_dict = dict.fromkeys(total_counter_dict.keys(), -1) + wf = Workflow(file_name.split(".", maxsplit=1)[0]) nodes_look_up_dict = {node["id"]: node["value"] for node in content[NODES_LABEL]} for node_dict in content[NODES_LABEL]: if node_dict["type"] == "function": @@ -384,7 +374,7 @@ def load_workflow_json(file_name: str) -> Workflow: source_port = edge_dict[SOURCE_PORT_LABEL] if source_port is None: - if source_id in input_values.keys(): # Parent input value + if source_id in input_values: # Parent input value upstream = input_values[source_id] else: # Single-output sibling upstream = nodes[source_id] diff --git a/src/python_workflow_definition/shared.py b/src/python_workflow_definition/shared.py index 9cc6680..746403c 100644 --- a/src/python_workflow_definition/shared.py +++ b/src/python_workflow_definition/shared.py @@ -34,7 +34,7 @@ def get_kwargs(lst: list) -> dict: def get_source_handles(edges_lst: list) -> dict: source_handle_dict: dict[Any, list] = {} for ed in edges_lst: - if ed[SOURCE_LABEL] not in source_handle_dict.keys(): + if ed[SOURCE_LABEL] not in source_handle_dict: source_handle_dict[ed[SOURCE_LABEL]] = [] source_handle_dict[ed[SOURCE_LABEL]].append(ed[SOURCE_PORT_LABEL]) return { @@ -67,7 +67,7 @@ def update_node_names(workflow_dict: dict) -> dict: } counter_dict = Counter(node_names_dict.values()) - node_names_useage_dict = {k: -1 for k in counter_dict.keys()} + node_names_useage_dict = dict.fromkeys(counter_dict.keys(), -1) for k, v in node_names_dict.items(): node_names_useage_dict[v] += 1 if counter_dict[v] > 1: From c422a77e58388e4781e107d2b7472d9f77fa7695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 27 Jul 2026 07:03:51 +0200 Subject: [PATCH 05/19] fixes --- pyproject.toml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ba59460..0046187 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,7 +66,12 @@ select = [ # pylint "PL", ] -ignore = [] +ignore = [ + # ignore line-length violations + "E501", + # Too many branches + "PLR0912", +] [tool.hatch.build] include = [ From 5898f5d346a29991c58194d79d47a0149a11e799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 27 Jul 2026 07:04:20 +0200 Subject: [PATCH 06/19] black fixes --- src/python_workflow_definition/cwl/__init__.py | 10 +++++++--- src/python_workflow_definition/pyiron_workflow.py | 6 +++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/python_workflow_definition/cwl/__init__.py b/src/python_workflow_definition/cwl/__init__.py index 96ae76e..7333a65 100644 --- a/src/python_workflow_definition/cwl/__init__.py +++ b/src/python_workflow_definition/cwl/__init__.py @@ -21,7 +21,8 @@ def _get_function_argument(argument: str, position: int = 3) -> dict: return { - argument + "_file": { + argument + + "_file": { "type": "File", "inputBinding": { "prefix": "--arg_" + argument + "=", @@ -44,7 +45,8 @@ def _get_function_template(function_name: str) -> dict: def _get_output_name(output_name: str) -> dict: return { - output_name + "_file": { + output_name + + "_file": { "type": "File", "outputBinding": {"glob": output_name + ".pickle"}, } @@ -225,7 +227,9 @@ def _write_workflow(workflow, directory_path: str = "."): ) workflow_template["steps"].update( { - step_name_lst[ind] + "_" + str(ind): { + step_name_lst[ind] + + "_" + + str(ind): { "run": node_script, "in": in_dict, "out": output, diff --git a/src/python_workflow_definition/pyiron_workflow.py b/src/python_workflow_definition/pyiron_workflow.py index 33f49a3..0af64ab 100644 --- a/src/python_workflow_definition/pyiron_workflow.py +++ b/src/python_workflow_definition/pyiron_workflow.py @@ -318,9 +318,9 @@ def load_workflow_json(file_name: str) -> Workflow: PythonWorkflowDefinitionWorkflow.load_json_file(file_name=file_name) ) - input_values: dict[ - int, object - ] = {} # Type is actually more restrictive, must be jsonifyable object + input_values: dict[int, object] = ( + {} + ) # Type is actually more restrictive, must be jsonifyable object nodes: dict[int, Function] = {} total_counter_dict = Counter( [n["value"] for n in content[NODES_LABEL] if n["type"] == "function"] From 8ad140dcea14ab4b9e63511dda264d372025cc73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 27 Jul 2026 07:07:04 +0200 Subject: [PATCH 07/19] fixes --- src/python_workflow_definition/cwl/__init__.py | 18 +++++++++--------- src/python_workflow_definition/jobflow.py | 10 +++------- src/python_workflow_definition/purepython.py | 2 +- src/python_workflow_definition/pyiron_base.py | 14 +++++++------- src/python_workflow_definition/shared.py | 14 +++++++------- 5 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/python_workflow_definition/cwl/__init__.py b/src/python_workflow_definition/cwl/__init__.py index 7333a65..b0333b2 100644 --- a/src/python_workflow_definition/cwl/__init__.py +++ b/src/python_workflow_definition/cwl/__init__.py @@ -60,22 +60,22 @@ def _get_function(workflow): funct_dict = {} for funct_id in function_nodes_dict: target_ports = list( - set( - [ + { + e[TARGET_PORT_LABEL] for e in workflow[EDGES_LABEL] if e["target"] == funct_id - ] - ) + + } ) source_ports = list( - set( - [ + { + e[SOURCE_PORT_LABEL] for e in workflow[EDGES_LABEL] if e["source"] == funct_id - ] - ) + + } ) funct_dict[funct_id] = { "targetPorts": target_ports, @@ -89,7 +89,7 @@ def _write_function_cwl(workflow, directory_path: str = "."): export_path = Path(directory_path) export_path.mkdir(parents=True, exist_ok=True) - for i in function_nodes_dict.keys(): + for i in function_nodes_dict: template: dict[str, Any] = { "cwlVersion": "v1.2", "class": "CommandLineTool", diff --git a/src/python_workflow_definition/jobflow.py b/src/python_workflow_definition/jobflow.py index 348c446..67868fa 100644 --- a/src/python_workflow_definition/jobflow.py +++ b/src/python_workflow_definition/jobflow.py @@ -79,13 +79,11 @@ def _get_edges_and_extend_nodes( ) ) elif isinstance(v, dict) and any( - [ - isinstance(el, dict) + isinstance(el, dict) and "@module" in el and "@class" in el and "@version" in el for el in v.values() - ] ): node_dict_index = len(nodes_dict) nodes_dict[node_dict_index] = get_dict @@ -129,13 +127,11 @@ def _get_edges_and_extend_nodes( } ) elif isinstance(v, list) and any( - [ - isinstance(el, dict) + isinstance(el, dict) and "@module" in el and "@class" in el and "@version" in el for el in v - ] ): node_list_index = len(nodes_dict) nodes_dict[node_list_index] = get_list @@ -206,7 +202,7 @@ def _resort_total_lst(total_dict: dict, nodes_dict: dict) -> dict: if ind not in ordered_lst: source_lst = [sd[SOURCE_LABEL] for sd in connect.values()] if all( - [s in ordered_lst or s in nodes_without_dep_lst for s in source_lst] + s in ordered_lst or s in nodes_without_dep_lst for s in source_lst ): ordered_lst.append(ind) total_new_dict[ind] = connect diff --git a/src/python_workflow_definition/purepython.py b/src/python_workflow_definition/purepython.py index 7d0407f..f541edc 100644 --- a/src/python_workflow_definition/purepython.py +++ b/src/python_workflow_definition/purepython.py @@ -25,7 +25,7 @@ def resort_total_lst(total_lst: list, nodes_dict: dict) -> list: if ind not in ordered_lst: source_lst = [sd[SOURCE_LABEL] for sd in connect.values()] if all( - [s in ordered_lst or s in nodes_without_dep_lst for s in source_lst] + s in ordered_lst or s in nodes_without_dep_lst for s in source_lst ): ordered_lst.append(ind) total_new_lst.append([ind, connect]) diff --git a/src/python_workflow_definition/pyiron_base.py b/src/python_workflow_definition/pyiron_base.py index eb92ec9..e9d3725 100644 --- a/src/python_workflow_definition/pyiron_base.py +++ b/src/python_workflow_definition/pyiron_base.py @@ -35,7 +35,7 @@ def _resort_total_lst(total_lst: list, nodes_dict: dict) -> list: if ind not in ordered_lst: source_lst = [sd[SOURCE_LABEL] for sd in connect.values()] if all( - [s in ordered_lst or s in nodes_without_dep_lst for s in source_lst] + s in ordered_lst or s in nodes_without_dep_lst for s in source_lst ): ordered_lst.append(ind) total_new_lst.append([ind, connect]) @@ -93,7 +93,7 @@ def _get_delayed_object_dict( def get_dict(**kwargs) -> dict: - return {k: v for k, v in kwargs["kwargs"].items()} + return dict(kwargs["kwargs"].items()) def get_list(**kwargs) -> list: @@ -120,12 +120,12 @@ def _get_unique_objects(nodes_dict: dict): for k, v in nodes_dict.items(): if isinstance(v, DelayedObject): delayed_object_dict[k] = v - elif isinstance(v, list) and any([isinstance(el, DelayedObject) for el in v]): + elif isinstance(v, list) and any(isinstance(el, DelayedObject) for el in v): delayed_object_dict[k] = DelayedObject(function=get_list) - delayed_object_dict[k]._input = {i: el for i, el in enumerate(v)} + delayed_object_dict[k]._input = dict(enumerate(v)) delayed_object_dict[k]._python_function = get_list elif isinstance(v, dict) and any( - [isinstance(el, DelayedObject) for el in v.values()] + isinstance(el, DelayedObject) for el in v.values() ): delayed_object_dict[k] = DelayedObject( function=get_dict, @@ -156,11 +156,11 @@ def _get_unique_objects(nodes_dict: dict): if not ( isinstance(v, DelayedObject) or ( - isinstance(v, list) and any([isinstance(el, DelayedObject) for el in v]) + isinstance(v, list) and any(isinstance(el, DelayedObject) for el in v) ) or ( isinstance(v, dict) - and any([isinstance(el, DelayedObject) for el in v.values()]) + and any(isinstance(el, DelayedObject) for el in v.values()) ) ): update_dict[k] = v diff --git a/src/python_workflow_definition/shared.py b/src/python_workflow_definition/shared.py index 746403c..affc9c5 100644 --- a/src/python_workflow_definition/shared.py +++ b/src/python_workflow_definition/shared.py @@ -13,7 +13,7 @@ def get_dict(**kwargs) -> dict: # NOTE: In WG, this will automatically be wrapped in a dict with the `result` key - return {k: v for k, v in kwargs.items()} + return dict(kwargs.items()) # return {'dict': {k: v for k, v in kwargs.items()}} @@ -38,7 +38,7 @@ def get_source_handles(edges_lst: list) -> dict: source_handle_dict[ed[SOURCE_LABEL]] = [] source_handle_dict[ed[SOURCE_LABEL]].append(ed[SOURCE_PORT_LABEL]) return { - k: list(range(len(v))) if len(v) > 1 and all([el is None for el in v]) else v + k: list(range(len(v))) if len(v) > 1 and all(el is None for el in v) else v for k, v in source_handle_dict.items() } @@ -55,13 +55,13 @@ def update_node_names(workflow_dict: dict) -> dict: input_nodes = [n for n in workflow_dict[NODES_LABEL] if n["type"] == "input"] node_names_dict = { n["id"]: list( - set( - [ + { + e[TARGET_PORT_LABEL] for e in workflow_dict[EDGES_LABEL] if e[SOURCE_LABEL] == n["id"] - ] - ) + + } )[0] for n in input_nodes } @@ -83,7 +83,7 @@ def update_node_names(workflow_dict: dict) -> dict: def set_result_node(workflow_dict): node_id_lst = [n["id"] for n in workflow_dict[NODES_LABEL]] - source_lst = list(set([e[SOURCE_LABEL] for e in workflow_dict[EDGES_LABEL]])) + source_lst = list({e[SOURCE_LABEL] for e in workflow_dict[EDGES_LABEL]}) end_node_lst = [] for ni in node_id_lst: From 9ae47bdd8cf46f6b53e2b2785f263cdb23d5dd4f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 27 Jul 2026 05:09:40 +0000 Subject: [PATCH 08/19] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../cwl/__init__.py | 26 +++++++------------ src/python_workflow_definition/jobflow.py | 16 ++++++------ src/python_workflow_definition/pyiron_base.py | 4 +-- .../pyiron_workflow.py | 6 ++--- src/python_workflow_definition/shared.py | 8 +++--- 5 files changed, 24 insertions(+), 36 deletions(-) diff --git a/src/python_workflow_definition/cwl/__init__.py b/src/python_workflow_definition/cwl/__init__.py index b0333b2..2bf0afc 100644 --- a/src/python_workflow_definition/cwl/__init__.py +++ b/src/python_workflow_definition/cwl/__init__.py @@ -21,8 +21,7 @@ def _get_function_argument(argument: str, position: int = 3) -> dict: return { - argument - + "_file": { + argument + "_file": { "type": "File", "inputBinding": { "prefix": "--arg_" + argument + "=", @@ -45,8 +44,7 @@ def _get_function_template(function_name: str) -> dict: def _get_output_name(output_name: str) -> dict: return { - output_name - + "_file": { + output_name + "_file": { "type": "File", "outputBinding": {"glob": output_name + ".pickle"}, } @@ -61,20 +59,16 @@ def _get_function(workflow): for funct_id in function_nodes_dict: target_ports = list( { - - e[TARGET_PORT_LABEL] - for e in workflow[EDGES_LABEL] - if e["target"] == funct_id - + e[TARGET_PORT_LABEL] + for e in workflow[EDGES_LABEL] + if e["target"] == funct_id } ) source_ports = list( { - - e[SOURCE_PORT_LABEL] - for e in workflow[EDGES_LABEL] - if e["source"] == funct_id - + e[SOURCE_PORT_LABEL] + for e in workflow[EDGES_LABEL] + if e["source"] == funct_id } ) funct_dict[funct_id] = { @@ -227,9 +221,7 @@ def _write_workflow(workflow, directory_path: str = "."): ) workflow_template["steps"].update( { - step_name_lst[ind] - + "_" - + str(ind): { + step_name_lst[ind] + "_" + str(ind): { "run": node_script, "in": in_dict, "out": output, diff --git a/src/python_workflow_definition/jobflow.py b/src/python_workflow_definition/jobflow.py index 67868fa..3d9e567 100644 --- a/src/python_workflow_definition/jobflow.py +++ b/src/python_workflow_definition/jobflow.py @@ -80,10 +80,10 @@ def _get_edges_and_extend_nodes( ) elif isinstance(v, dict) and any( isinstance(el, dict) - and "@module" in el - and "@class" in el - and "@version" in el - for el in v.values() + and "@module" in el + and "@class" in el + and "@version" in el + for el in v.values() ): node_dict_index = len(nodes_dict) nodes_dict[node_dict_index] = get_dict @@ -128,10 +128,10 @@ def _get_edges_and_extend_nodes( ) elif isinstance(v, list) and any( isinstance(el, dict) - and "@module" in el - and "@class" in el - and "@version" in el - for el in v + and "@module" in el + and "@class" in el + and "@version" in el + for el in v ): node_list_index = len(nodes_dict) nodes_dict[node_list_index] = get_list diff --git a/src/python_workflow_definition/pyiron_base.py b/src/python_workflow_definition/pyiron_base.py index e9d3725..fdfae42 100644 --- a/src/python_workflow_definition/pyiron_base.py +++ b/src/python_workflow_definition/pyiron_base.py @@ -155,9 +155,7 @@ def _get_unique_objects(nodes_dict: dict): for k, v in nodes_dict.items(): if not ( isinstance(v, DelayedObject) - or ( - isinstance(v, list) and any(isinstance(el, DelayedObject) for el in v) - ) + or (isinstance(v, list) and any(isinstance(el, DelayedObject) for el in v)) or ( isinstance(v, dict) and any(isinstance(el, DelayedObject) for el in v.values()) diff --git a/src/python_workflow_definition/pyiron_workflow.py b/src/python_workflow_definition/pyiron_workflow.py index 0af64ab..33f49a3 100644 --- a/src/python_workflow_definition/pyiron_workflow.py +++ b/src/python_workflow_definition/pyiron_workflow.py @@ -318,9 +318,9 @@ def load_workflow_json(file_name: str) -> Workflow: PythonWorkflowDefinitionWorkflow.load_json_file(file_name=file_name) ) - input_values: dict[int, object] = ( - {} - ) # Type is actually more restrictive, must be jsonifyable object + input_values: dict[ + int, object + ] = {} # Type is actually more restrictive, must be jsonifyable object nodes: dict[int, Function] = {} total_counter_dict = Counter( [n["value"] for n in content[NODES_LABEL] if n["type"] == "function"] diff --git a/src/python_workflow_definition/shared.py b/src/python_workflow_definition/shared.py index affc9c5..d3ed347 100644 --- a/src/python_workflow_definition/shared.py +++ b/src/python_workflow_definition/shared.py @@ -56,11 +56,9 @@ def update_node_names(workflow_dict: dict) -> dict: node_names_dict = { n["id"]: list( { - - e[TARGET_PORT_LABEL] - for e in workflow_dict[EDGES_LABEL] - if e[SOURCE_LABEL] == n["id"] - + e[TARGET_PORT_LABEL] + for e in workflow_dict[EDGES_LABEL] + if e[SOURCE_LABEL] == n["id"] } )[0] for n in input_nodes From 6fc3070d20e0ad95611344cff9de551dd71c5a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 27 Jul 2026 07:16:26 +0200 Subject: [PATCH 09/19] remove commended out code --- src/python_workflow_definition/shared.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/python_workflow_definition/shared.py b/src/python_workflow_definition/shared.py index d3ed347..fe42cfc 100644 --- a/src/python_workflow_definition/shared.py +++ b/src/python_workflow_definition/shared.py @@ -12,9 +12,7 @@ def get_dict(**kwargs) -> dict: - # NOTE: In WG, this will automatically be wrapped in a dict with the `result` key return dict(kwargs.items()) - # return {'dict': {k: v for k, v in kwargs.items()}} def get_list(**kwargs) -> list: From c6036ef063e6112448bb000803f164c12b59b925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 27 Jul 2026 07:20:38 +0200 Subject: [PATCH 10/19] more fixes --- pyproject.toml | 2 ++ src/python_workflow_definition/jobflow.py | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0046187..04e61b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,6 +69,8 @@ select = [ ignore = [ # ignore line-length violations "E501", + # Too many statements + "PLR0915", # Too many branches "PLR0912", ] diff --git a/src/python_workflow_definition/jobflow.py b/src/python_workflow_definition/jobflow.py index 3d9e567..7f4e43c 100644 --- a/src/python_workflow_definition/jobflow.py +++ b/src/python_workflow_definition/jobflow.py @@ -27,7 +27,7 @@ def _get_function_dict(flow: Flow): - return {job.uuid: job.function for job in flow.jobs} + return {j.uuid: j.function for j in flow.jobs} def _get_nodes_dict(function_dict: dict): @@ -62,8 +62,8 @@ def _get_edges_and_extend_nodes( flow_dict: dict, nodes_mapping_dict: dict, nodes_dict: dict ): edges_lst = [] - for job in flow_dict["jobs"]: - for k, v in job["function_kwargs"].items(): + for j in flow_dict["jobs"]: + for k, v in j["function_kwargs"].items(): if ( isinstance(v, dict) and "@module" in v @@ -72,7 +72,7 @@ def _get_edges_and_extend_nodes( ): edges_lst.append( _get_edge_from_dict( - target=nodes_mapping_dict[job["uuid"]], + target=nodes_mapping_dict[j["uuid"]], key=k, value_dict=v, nodes_mapping_dict=nodes_mapping_dict, @@ -120,7 +120,7 @@ def _get_edges_and_extend_nodes( ) edges_lst.append( { - TARGET_LABEL: nodes_mapping_dict[job["uuid"]], + TARGET_LABEL: nodes_mapping_dict[j["uuid"]], TARGET_PORT_LABEL: k, SOURCE_LABEL: node_dict_index, SOURCE_PORT_LABEL: None, @@ -168,7 +168,7 @@ def _get_edges_and_extend_nodes( ) edges_lst.append( { - TARGET_LABEL: nodes_mapping_dict[job["uuid"]], + TARGET_LABEL: nodes_mapping_dict[j["uuid"]], TARGET_PORT_LABEL: k, SOURCE_LABEL: node_list_index, SOURCE_PORT_LABEL: None, @@ -182,7 +182,7 @@ def _get_edges_and_extend_nodes( node_index = {tv: tk for tk, tv in nodes_dict.items()}[v] edges_lst.append( { - TARGET_LABEL: nodes_mapping_dict[job["uuid"]], + TARGET_LABEL: nodes_mapping_dict[j["uuid"]], TARGET_PORT_LABEL: k, SOURCE_LABEL: node_index, SOURCE_PORT_LABEL: None, From e36659bd6e2c95b0658d23bcac6f148c6a395ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 27 Jul 2026 07:23:01 +0200 Subject: [PATCH 11/19] type fix --- src/python_workflow_definition/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/python_workflow_definition/models.py b/src/python_workflow_definition/models.py index 8265132..0f76481 100644 --- a/src/python_workflow_definition/models.py +++ b/src/python_workflow_definition/models.py @@ -1,7 +1,7 @@ import json import logging from pathlib import Path -from typing import Annotated, Any, Literal, TypeVar, Union +from typing import Annotated, Any, Literal, TypeVar, Union, Optional from pydantic import ( BaseModel, @@ -26,7 +26,7 @@ ) -JsonPrimitive = Union[str, int, float, bool, None] +JsonPrimitive = Optional[str | int | float | bool] AllowableDefaults = TypeAliasType( "AllowableDefaults", "JsonPrimitive | dict[str, AllowableDefaults] | list[AllowableDefaults]", From aed8d8af63152803bc42a3735f77b6d2840a239a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 27 Jul 2026 07:24:17 +0200 Subject: [PATCH 12/19] more fixes --- src/python_workflow_definition/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/python_workflow_definition/models.py b/src/python_workflow_definition/models.py index 0f76481..167fa47 100644 --- a/src/python_workflow_definition/models.py +++ b/src/python_workflow_definition/models.py @@ -1,7 +1,7 @@ import json import logging from pathlib import Path -from typing import Annotated, Any, Literal, TypeVar, Union, Optional +from typing import Annotated, Any, Literal, TypeVar from pydantic import ( BaseModel, @@ -26,7 +26,7 @@ ) -JsonPrimitive = Optional[str | int | float | bool] +JsonPrimitive = str | int | float | bool | None AllowableDefaults = TypeAliasType( "AllowableDefaults", "JsonPrimitive | dict[str, AllowableDefaults] | list[AllowableDefaults]", From 68f3ee9d205f1c29f8c6d6c94691eb5f18e8ce4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 27 Jul 2026 07:29:55 +0200 Subject: [PATCH 13/19] more fixes --- src/python_workflow_definition/jobflow.py | 4 ++-- src/python_workflow_definition/pyiron_base.py | 8 ++++---- src/python_workflow_definition/pyiron_workflow.py | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/python_workflow_definition/jobflow.py b/src/python_workflow_definition/jobflow.py index 7f4e43c..a4dfb05 100644 --- a/src/python_workflow_definition/jobflow.py +++ b/src/python_workflow_definition/jobflow.py @@ -236,7 +236,7 @@ def get_attr_helper(obj, source_handle): return getattr(obj.output, source_handle) memory_dict: dict[Any, Any] = {} - for k in total_dict: + for k, subdict in total_dict.items(): v = nodes_dict[k] if isfunction(v): if k in source_handles_dict: @@ -255,7 +255,7 @@ def get_attr_helper(obj, source_handle): source_handle=vw[SOURCE_PORT_LABEL], ) ) - for kw, vw in total_dict[k].items() + for kw, vw in subdict.items() } memory_dict[k] = fn(**kwargs) return list(memory_dict.values()) diff --git a/src/python_workflow_definition/pyiron_base.py b/src/python_workflow_definition/pyiron_base.py index fdfae42..ae34b1b 100644 --- a/src/python_workflow_definition/pyiron_base.py +++ b/src/python_workflow_definition/pyiron_base.py @@ -136,13 +136,13 @@ def _get_unique_objects(nodes_dict: dict): unique_lst: list = [] delayed_object_updated_dict: dict[Any, DelayedObject] = {} match_dict: dict[Any, Any] = {} - for dobj in delayed_object_dict: + for dobj, v in delayed_object_dict.items(): match = False for obj in unique_lst: if ( delayed_object_updated_dict[obj]._python_function - == delayed_object_dict[dobj]._python_function - and delayed_object_dict[dobj]._input == delayed_object_dict[obj]._input + == v._python_function + and v._input == delayed_object_dict[obj]._input ): delayed_object_updated_dict[obj] = delayed_object_dict[obj] match_dict[dobj] = obj @@ -150,7 +150,7 @@ def _get_unique_objects(nodes_dict: dict): break if not match: unique_lst.append(dobj) - delayed_object_updated_dict[dobj] = delayed_object_dict[dobj] + delayed_object_updated_dict[dobj] = v update_dict = {} for k, v in nodes_dict.items(): if not ( diff --git a/src/python_workflow_definition/pyiron_workflow.py b/src/python_workflow_definition/pyiron_workflow.py index 33f49a3..5177643 100644 --- a/src/python_workflow_definition/pyiron_workflow.py +++ b/src/python_workflow_definition/pyiron_workflow.py @@ -205,9 +205,9 @@ def write_workflow_json(graph_as_dict: dict, file_name: str = "workflow.json"): source_dict[k].append(edge) edge_new_lst, nodes_to_delete = [], [] - for k in target_dict: + for k, v in target_dict.items(): source, sourcehandle = None, None - for edge in target_dict[k]: + for edge in v: if edge[SOURCE_PORT_LABEL] is None: sourcehandle = nodes_dict[edge[SOURCE_LABEL]] nodes_to_delete.append(edge[SOURCE_LABEL]) From 74def5261a593422f9fe4522840078f9a78ca669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 27 Jul 2026 07:34:28 +0200 Subject: [PATCH 14/19] black fixes --- src/python_workflow_definition/cwl/__init__.py | 10 +++++++--- src/python_workflow_definition/pyiron_base.py | 3 +-- src/python_workflow_definition/pyiron_workflow.py | 6 +++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/python_workflow_definition/cwl/__init__.py b/src/python_workflow_definition/cwl/__init__.py index 2bf0afc..16a6e9d 100644 --- a/src/python_workflow_definition/cwl/__init__.py +++ b/src/python_workflow_definition/cwl/__init__.py @@ -21,7 +21,8 @@ def _get_function_argument(argument: str, position: int = 3) -> dict: return { - argument + "_file": { + argument + + "_file": { "type": "File", "inputBinding": { "prefix": "--arg_" + argument + "=", @@ -44,7 +45,8 @@ def _get_function_template(function_name: str) -> dict: def _get_output_name(output_name: str) -> dict: return { - output_name + "_file": { + output_name + + "_file": { "type": "File", "outputBinding": {"glob": output_name + ".pickle"}, } @@ -221,7 +223,9 @@ def _write_workflow(workflow, directory_path: str = "."): ) workflow_template["steps"].update( { - step_name_lst[ind] + "_" + str(ind): { + step_name_lst[ind] + + "_" + + str(ind): { "run": node_script, "in": in_dict, "out": output, diff --git a/src/python_workflow_definition/pyiron_base.py b/src/python_workflow_definition/pyiron_base.py index ae34b1b..53ee1a7 100644 --- a/src/python_workflow_definition/pyiron_base.py +++ b/src/python_workflow_definition/pyiron_base.py @@ -140,8 +140,7 @@ def _get_unique_objects(nodes_dict: dict): match = False for obj in unique_lst: if ( - delayed_object_updated_dict[obj]._python_function - == v._python_function + delayed_object_updated_dict[obj]._python_function == v._python_function and v._input == delayed_object_dict[obj]._input ): delayed_object_updated_dict[obj] = delayed_object_dict[obj] diff --git a/src/python_workflow_definition/pyiron_workflow.py b/src/python_workflow_definition/pyiron_workflow.py index 5177643..30c2a77 100644 --- a/src/python_workflow_definition/pyiron_workflow.py +++ b/src/python_workflow_definition/pyiron_workflow.py @@ -318,9 +318,9 @@ def load_workflow_json(file_name: str) -> Workflow: PythonWorkflowDefinitionWorkflow.load_json_file(file_name=file_name) ) - input_values: dict[ - int, object - ] = {} # Type is actually more restrictive, must be jsonifyable object + input_values: dict[int, object] = ( + {} + ) # Type is actually more restrictive, must be jsonifyable object nodes: dict[int, Function] = {} total_counter_dict = Counter( [n["value"] for n in content[NODES_LABEL] if n["type"] == "function"] From d642f29b1301296e6c2d83954f05590797532595 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 27 Jul 2026 05:34:50 +0000 Subject: [PATCH 15/19] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/python_workflow_definition/cwl/__init__.py | 10 +++------- src/python_workflow_definition/pyiron_workflow.py | 6 +++--- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/python_workflow_definition/cwl/__init__.py b/src/python_workflow_definition/cwl/__init__.py index 16a6e9d..2bf0afc 100644 --- a/src/python_workflow_definition/cwl/__init__.py +++ b/src/python_workflow_definition/cwl/__init__.py @@ -21,8 +21,7 @@ def _get_function_argument(argument: str, position: int = 3) -> dict: return { - argument - + "_file": { + argument + "_file": { "type": "File", "inputBinding": { "prefix": "--arg_" + argument + "=", @@ -45,8 +44,7 @@ def _get_function_template(function_name: str) -> dict: def _get_output_name(output_name: str) -> dict: return { - output_name - + "_file": { + output_name + "_file": { "type": "File", "outputBinding": {"glob": output_name + ".pickle"}, } @@ -223,9 +221,7 @@ def _write_workflow(workflow, directory_path: str = "."): ) workflow_template["steps"].update( { - step_name_lst[ind] - + "_" - + str(ind): { + step_name_lst[ind] + "_" + str(ind): { "run": node_script, "in": in_dict, "out": output, diff --git a/src/python_workflow_definition/pyiron_workflow.py b/src/python_workflow_definition/pyiron_workflow.py index 30c2a77..5177643 100644 --- a/src/python_workflow_definition/pyiron_workflow.py +++ b/src/python_workflow_definition/pyiron_workflow.py @@ -318,9 +318,9 @@ def load_workflow_json(file_name: str) -> Workflow: PythonWorkflowDefinitionWorkflow.load_json_file(file_name=file_name) ) - input_values: dict[int, object] = ( - {} - ) # Type is actually more restrictive, must be jsonifyable object + input_values: dict[ + int, object + ] = {} # Type is actually more restrictive, must be jsonifyable object nodes: dict[int, Function] = {} total_counter_dict = Counter( [n["value"] for n in content[NODES_LABEL] if n["type"] == "function"] From 8ac833667efa063a7357688b27fe8af8d2437406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 27 Jul 2026 07:41:22 +0200 Subject: [PATCH 16/19] black fixes --- .../cwl/__init__.py | 31 ++++++++++--------- .../pyiron_workflow.py | 4 +-- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/python_workflow_definition/cwl/__init__.py b/src/python_workflow_definition/cwl/__init__.py index 2bf0afc..af465c5 100644 --- a/src/python_workflow_definition/cwl/__init__.py +++ b/src/python_workflow_definition/cwl/__init__.py @@ -20,14 +20,15 @@ def _get_function_argument(argument: str, position: int = 3) -> dict: + input_dict = { + "prefix": "--arg_" + argument + "=", + "separate": False, + "position": position, + } return { argument + "_file": { "type": "File", - "inputBinding": { - "prefix": "--arg_" + argument + "=", - "separate": False, - "position": position, - }, + "inputBinding": input_dict, }, } @@ -43,11 +44,12 @@ def _get_function_template(function_name: str) -> dict: def _get_output_name(output_name: str) -> dict: + output_dict = { + "type": "File", + "outputBinding": {"glob": output_name + ".pickle"}, + } return { - output_name + "_file": { - "type": "File", - "outputBinding": {"glob": output_name + ".pickle"}, - } + output_name + "_file": output_dict } @@ -219,13 +221,14 @@ def _write_workflow(workflow, directory_path: str = "."): + v[SOURCE_PORT_LABEL] + "_file" ) + step_dict = { + "run": node_script, + "in": in_dict, + "out": output, + } workflow_template["steps"].update( { - step_name_lst[ind] + "_" + str(ind): { - "run": node_script, - "in": in_dict, - "out": output, - } + step_name_lst[ind] + "_" + str(ind): step_dict } ) export_path = Path(directory_path) diff --git a/src/python_workflow_definition/pyiron_workflow.py b/src/python_workflow_definition/pyiron_workflow.py index 5177643..ffdcd5b 100644 --- a/src/python_workflow_definition/pyiron_workflow.py +++ b/src/python_workflow_definition/pyiron_workflow.py @@ -318,9 +318,7 @@ def load_workflow_json(file_name: str) -> Workflow: PythonWorkflowDefinitionWorkflow.load_json_file(file_name=file_name) ) - input_values: dict[ - int, object - ] = {} # Type is actually more restrictive, must be jsonifyable object + input_values: dict[int, object] = {} nodes: dict[int, Function] = {} total_counter_dict = Counter( [n["value"] for n in content[NODES_LABEL] if n["type"] == "function"] From f3b0e93c6c1e93a50d794552ddbac8d451894666 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 27 Jul 2026 05:42:10 +0000 Subject: [PATCH 17/19] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/python_workflow_definition/cwl/__init__.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/python_workflow_definition/cwl/__init__.py b/src/python_workflow_definition/cwl/__init__.py index af465c5..ee5961e 100644 --- a/src/python_workflow_definition/cwl/__init__.py +++ b/src/python_workflow_definition/cwl/__init__.py @@ -48,9 +48,7 @@ def _get_output_name(output_name: str) -> dict: "type": "File", "outputBinding": {"glob": output_name + ".pickle"}, } - return { - output_name + "_file": output_dict - } + return {output_name + "_file": output_dict} def _get_function(workflow): @@ -227,9 +225,7 @@ def _write_workflow(workflow, directory_path: str = "."): "out": output, } workflow_template["steps"].update( - { - step_name_lst[ind] + "_" + str(ind): step_dict - } + {step_name_lst[ind] + "_" + str(ind): step_dict} ) export_path = Path(directory_path) export_path.mkdir(parents=True, exist_ok=True) From eed7dee45880b49b24ed95b36f46eb73039ca0ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 27 Jul 2026 07:44:24 +0200 Subject: [PATCH 18/19] fix --- src/python_workflow_definition/cwl/__init__.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/python_workflow_definition/cwl/__init__.py b/src/python_workflow_definition/cwl/__init__.py index af465c5..5d090b2 100644 --- a/src/python_workflow_definition/cwl/__init__.py +++ b/src/python_workflow_definition/cwl/__init__.py @@ -20,16 +20,16 @@ def _get_function_argument(argument: str, position: int = 3) -> dict: - input_dict = { - "prefix": "--arg_" + argument + "=", - "separate": False, - "position": position, + argument_dict = { + "type": "File", + "inputBinding": { + "prefix": "--arg_" + argument + "=", + "separate": False, + "position": position, + }, } return { - argument + "_file": { - "type": "File", - "inputBinding": input_dict, - }, + argument + "_file": argument_dict } From 6419104ab155708e10071df9cd1612a1e05a7b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Mon, 27 Jul 2026 07:45:01 +0200 Subject: [PATCH 19/19] black formatting --- src/python_workflow_definition/cwl/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/python_workflow_definition/cwl/__init__.py b/src/python_workflow_definition/cwl/__init__.py index afb8454..e8bf3ea 100644 --- a/src/python_workflow_definition/cwl/__init__.py +++ b/src/python_workflow_definition/cwl/__init__.py @@ -28,9 +28,7 @@ def _get_function_argument(argument: str, position: int = 3) -> dict: "position": position, }, } - return { - argument + "_file": argument_dict - } + return {argument + "_file": argument_dict} def _get_function_template(function_name: str) -> dict: