{"id":29656584,"url":"https://github.com/zincware/znflow","last_synced_at":"2025-07-22T08:36:03.288Z","repository":{"id":65878143,"uuid":"590372665","full_name":"zincware/ZnFlow","owner":"zincware","description":"A general purpose framework for building and running computational graphs.","archived":false,"fork":false,"pushed_at":"2025-06-23T19:34:30.000Z","size":1226,"stargazers_count":6,"open_issues_count":23,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-06-23T20:31:02.621Z","etag":null,"topics":["computational-graphs","directed-acyclic-graph","networkx","networkx-graph","python","python3","workflow"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zincware.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-01-18T09:06:45.000Z","updated_at":"2025-02-20T11:04:00.000Z","dependencies_parsed_at":"2023-10-03T13:14:13.266Z","dependency_job_id":"35900169-5682-4e1a-839a-dabb35903f2e","html_url":"https://github.com/zincware/ZnFlow","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/zincware/ZnFlow","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zincware%2FZnFlow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zincware%2FZnFlow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zincware%2FZnFlow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zincware%2FZnFlow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zincware","download_url":"https://codeload.github.com/zincware/ZnFlow/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zincware%2FZnFlow/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266456424,"owners_count":23931408,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["computational-graphs","directed-acyclic-graph","networkx","networkx-graph","python","python3","workflow"],"created_at":"2025-07-22T08:36:02.055Z","updated_at":"2025-07-22T08:36:03.251Z","avatar_url":"https://github.com/zincware.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![zincware](https://img.shields.io/badge/Powered%20by-zincware-darkcyan)](https://github.com/zincware)\n[![Coverage Status](https://coveralls.io/repos/github/zincware/ZnFlow/badge.svg?branch=main)](https://coveralls.io/github/zincware/ZnFlow?branch=main)\n[![PyPI version](https://badge.fury.io/py/znflow.svg)](https://badge.fury.io/py/znflow)\n[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/zincware/ZnFlow/HEAD)\n[![Discord](https://img.shields.io/discord/1034511611802689557)](https://discord.gg/7ncfwhsnm4)\n\n# ZnFlow\n\nThe `ZnFlow` package provides a basic structure for building computational\ngraphs based on functions or classes. It is designed as a lightweight\nabstraction layer to\n\n- learn graph computing.\n- build your own packages on top of it.\n\n## Installation\n\n```shell\npip install znflow\n```\n\n## Usage\n\n### Connecting Functions\n\nWith ZnFlow you can connect functions to each other by using the `@nodify`\ndecorator. Inside the `znflow.DiGraph` the decorator will return a\n`FunctionFuture` object that can be used to connect the function to other nodes.\nThe `FunctionFuture` object will also be used to retrieve the result of the\nfunction. Outside the `znflow.DiGraph` the function behaves as a normal\nfunction.\n\n```python\nimport znflow\n\n@znflow.nodify\ndef compute_mean(x, y):\n    return (x + y) / 2\n\nprint(compute_mean(2, 8))\n# \u003e\u003e\u003e 5\n\nwith znflow.DiGraph() as graph:\n    mean = compute_mean(2, 8)\n\ngraph.run()\nprint(mean.result)\n# \u003e\u003e\u003e 5\n\nwith znflow.DiGraph() as graph:\n    n1 = compute_mean(2, 8)\n    n2 = compute_mean(13, 7)\n    n3 = compute_mean(n1, n2)\n\ngraph.run()\nprint(n3.result)\n# \u003e\u003e\u003e 7.5\n```\n\n### Connecting Classes\n\nIt is also possible to connect classes. They can be connected either directly or\nvia class attributes. This is possible by returning `znflow.Connections` inside\nthe `znflow.DiGraph` context manager. Outside the `znflow.DiGraph` the class\nbehaves as a normal class.\n\nIn the following example we use a dataclass, but it works with all Python\nclasses that inherit from `znflow.Node`.\n\n```python\nimport znflow\nimport dataclasses\n\n@znflow.nodify\ndef compute_mean(x, y):\n    return (x + y) / 2\n\n@dataclasses.dataclass\nclass ComputeMean(znflow.Node):\n    x: float\n    y: float\n\n    results: float = None\n\n    def run(self):\n        self.results = (self.x + self.y) / 2\n\nwith znflow.DiGraph() as graph:\n    n1 = ComputeMean(2, 8)\n    n2 = compute_mean(13, 7)\n    # connecting classes and functions to a Node\n    n3 = ComputeMean(n1.results, n2)\n\ngraph.run()\nprint(n3.results)\n# \u003e\u003e\u003e 7.5\n```\n\n### Dask Support\n\nZnFlow comes with support for [Dask](https://www.dask.org/) to run your graph:\n\n- in parallel.\n- through e.g. SLURM (see https://jobqueue.dask.org/en/latest/api.html).\n- with a nice GUI to track progress.\n\nAll you need to do is install ZnFlow with Dask `pip install znflow[dask]`. We\ncan then extend the example from above. This will run `n1` and `n2` in parallel.\nYou can investigate the graph on the Dask dashboard (typically\nhttp://127.0.0.1:8787/graph or via the client object in Jupyter.)\n\n```python\nimport znflow\nimport dataclasses\nfrom dask.distributed import Client\n\n@znflow.nodify\ndef compute_mean(x, y):\n    return (x + y) / 2\n\n@dataclasses.dataclass\nclass ComputeMean(znflow.Node):\n    x: float\n    y: float\n\n    results: float = None\n\n    def run(self):\n        self.results = (self.x + self.y) / 2\n\n\nclient = Client()\ndeployment = znflow.deployment.DaskDeployment(client=client)\n\n\nwith znflow.DiGraph(deployment=deployment) as graph:\n    n1 = ComputeMean(2, 8)\n    n2 = compute_mean(13, 7)\n    # connecting classes and functions to a Node\n    n3 = ComputeMean(n1.results, n2)\n\ngraph.run()\n\nprint(n3)\n# \u003e\u003e\u003e ComputeMean(x=5.0, y=10.0, results=7.5)\n```\n\n### Working with lists\n\nZnFlow supports some special features for working with lists. In the following\nexample we want to `combine` two lists.\n\n```python\nimport znflow\n\n@znflow.nodify\ndef arange(size: int) -\u003e list:\n    return list(range(size))\n\nprint(arange(2) + arange(3))\n\u003e\u003e\u003e [0, 1, 0, 1, 2]\n\nwith znflow.DiGraph() as graph:\n    lst = arange(2) + arange(3)\n\ngraph.run()\nprint(lst.result)\n\u003e\u003e\u003e [0, 1, 0, 1, 2]\n```\n\nThis functionality is restricted to lists. There are some further features that\nallow combining `data: list[list]` by either using\n`data: list = znflow.combine(data)` which has an optional `attribute=None`\nargument to be used in the case of classes or you can simply use\n`data: list = sum(data, [])`.\n\n### Attributes Access\n\nInside the `with znflow.DiGraph()` context manager, accessing class attributes\nyields `znflow.Connector` objects. Sometimes, it may be required to obtain the\nactual attribute value instead of a `znflow.Connector` object. It is not\nrecommended to run class methods inside the `with znflow.DiGraph()` context\nmanager since it should be exclusively used for building the graph and not for\nactual computation.\n\nIn the case of properties or other descriptor-based attributes, it might be\nnecessary to access the actual attribute value. This can be achieved using the\n`znflow.get_attribute` method, which supports all features from `getattr` and\ncan be imported as such:\n\n```python\nfrom znflow import get_attribute as getattr\n```\n\nHere's an example of how to use `znflow.get_attribute`:\n\n```python\nimport znflow\n\nclass POW2(znflow.Node):\n    \"\"\"Compute the square of x.\"\"\"\n    x_factor: float = 0.5\n    results: float = None\n    _x: float = None\n\n    @property\n    def x(self):\n        return self._x\n\n    @x.setter\n    def x(self, value):\n        # using \"self._x = value * self.x_factor\" inside \"znflow.DiGraph()\" would run\n        # \"value * Connector(self, \"x_factor\")\" which is not possible (TypeError)\n        # therefore we use znflow.get_attribute.\n        self._x = value * znflow.get_attribute(self, \"x_factor\")\n\n    def run(self):\n        self.results = self.x**2\n\nwith znflow.DiGraph() as graph:\n    n1 = POW2()\n    n1.x = 4.0\n\ngraph.run()\nassert n1.results == 4.0\n\n```\n\nInstead, you can also use the `znflow.disable_graph` decorator / context manager\nto disable the graph for a specific block of code or the `znflow.Property` as a\ndrop-in replacement for `property`.\n\n### Groups\n\nIt is possible to create groups of `znflow.nodify` or `znflow.Nodes` independent\nfrom the graph structure. To create a group you can use\n`with graph.group(\u003cname\u003e)`. To access the group members, use\n`graph.get_group(\u003cname\u003e) -\u003e znflow.Group`.\n\n```python\nimport znflow\n\n@znflow.nodify\ndef compute_mean(x, y):\n    return (x + y) / 2\n\ngraph = znflow.DiGraph()\n\nwith graph.group(\"grp1\"):\n    n1 = compute_mean(2, 4)\n\nassert n1.uuid in graph.get_group(\"grp1\")\n```\n\n## Supported Frameworks\n\nZnFlow includes tests to ensure compatibility with:\n\n- \"Plain classes\"\n- `dataclasses`\n- `ZnInit`\n- `attrs`\n- `pydantic` (experimental)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzincware%2Fznflow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzincware%2Fznflow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzincware%2Fznflow/lists"}