async-graph-data-flow 1.5.1__tar.gz → 1.6.0__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.
Files changed (20) hide show
  1. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0}/CHANGELOG.md +13 -0
  2. {async_graph_data_flow-1.5.1/src/async_graph_data_flow.egg-info → async_graph_data_flow-1.6.0}/PKG-INFO +9 -9
  3. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0}/README.md +1 -1
  4. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0}/pyproject.toml +7 -7
  5. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow/executor.py +6 -2
  6. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow/graph.py +34 -10
  7. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0/src/async_graph_data_flow.egg-info}/PKG-INFO +9 -9
  8. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow.egg-info/requires.txt +6 -6
  9. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0}/tests/test_graph.py +3 -0
  10. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0}/LICENSE.txt +0 -0
  11. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0}/MANIFEST.in +0 -0
  12. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0}/setup.cfg +0 -0
  13. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow/__init__.py +0 -0
  14. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow/py.typed +0 -0
  15. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow.egg-info/SOURCES.txt +0 -0
  16. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow.egg-info/dependency_links.txt +0 -0
  17. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow.egg-info/not-zip-safe +0 -0
  18. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow.egg-info/top_level.txt +0 -0
  19. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0}/tests/test_executor.py +0 -0
  20. {async_graph_data_flow-1.5.1 → async_graph_data_flow-1.6.0}/tests/test_version_number.py +0 -0
@@ -19,6 +19,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
19
19
 
20
20
  ### Security
21
21
 
22
+ ## [1.6.0] - 2025-03-19
23
+
24
+ ### Added
25
+ - Added support for custom edge behaviors, through the new `queue` argument at `add_node`
26
+ for a custom queue object. (#14)
27
+
28
+ ### Deprecated
29
+ - Deprecated the `queue_size` argument at `add_node` -- use the new `queue` instead. (#14)
30
+
31
+ ### Security
32
+ - Resolved CVE-2024-56326, CVE-2024-56201, and CVE-2025-27516
33
+ by updating jinja2 to v3.1.6 in requirements for Sphinx docs. (#14)
34
+
22
35
  ## [1.5.1] - 2024-11-07
23
36
 
24
37
  ### Added
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: async-graph-data-flow
3
- Version: 1.5.1
3
+ Version: 1.6.0
4
4
  Summary: Asynchronous functions that pass data along a directed acyclic graph
5
5
  Author-email: Civis Analytics <opensource@civisanalytics.com>
6
6
  License: BSD 3-Clause
@@ -24,14 +24,14 @@ Requires-Python: >=3.10
24
24
  Description-Content-Type: text/markdown
25
25
  License-File: LICENSE.txt
26
26
  Provides-Extra: dev
27
- Requires-Dist: black==24.10.0; extra == "dev"
28
- Requires-Dist: flake8==7.1.1; extra == "dev"
29
- Requires-Dist: pytest==8.3.3; extra == "dev"
30
- Requires-Dist: mypy==1.13.0; extra == "dev"
27
+ Requires-Dist: black==25.1.0; extra == "dev"
28
+ Requires-Dist: flake8==7.1.2; extra == "dev"
29
+ Requires-Dist: pytest==8.3.5; extra == "dev"
30
+ Requires-Dist: mypy==1.15.0; extra == "dev"
31
31
  Requires-Dist: build==1.2.2; extra == "dev"
32
- Requires-Dist: twine==5.1.1; extra == "dev"
32
+ Requires-Dist: twine==6.1.0; extra == "dev"
33
33
  Provides-Extra: docs
34
- Requires-Dist: Sphinx==8.1.3; extra == "docs"
34
+ Requires-Dist: Sphinx==8.2.3; extra == "docs"
35
35
  Requires-Dist: furo==2024.8.6; extra == "docs"
36
36
  Requires-Dist: numpydoc==1.8.0; extra == "docs"
37
37
  Requires-Dist: sphinx-copybutton==0.5.2; extra == "docs"
@@ -77,7 +77,7 @@ black --check src tests examples
77
77
 
78
78
  ## Building Documentation
79
79
 
80
- We use the Sphinx framework. The documentation source files are in `docs/source/`.
80
+ We use the Sphinx framework. The documentation source files are in `docs/`.
81
81
  These files can be updated as necessary.
82
82
 
83
83
  The public documentation is accessible at https://async-graph-data-flow.readthedocs.io.
@@ -38,7 +38,7 @@ black --check src tests examples
38
38
 
39
39
  ## Building Documentation
40
40
 
41
- We use the Sphinx framework. The documentation source files are in `docs/source/`.
41
+ We use the Sphinx framework. The documentation source files are in `docs/`.
42
42
  These files can be updated as necessary.
43
43
 
44
44
  The public documentation is accessible at https://async-graph-data-flow.readthedocs.io.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "async-graph-data-flow"
7
- version = "1.5.1"
7
+ version = "1.6.0"
8
8
  description = "Asynchronous functions that pass data along a directed acyclic graph"
9
9
  readme = "README.md"
10
10
  requires-python = ">= 3.10"
@@ -40,17 +40,17 @@ Source = "https://github.com/civisanalytics/async-graph-data-flow"
40
40
  [project.optional-dependencies]
41
41
  dev = [
42
42
  # Running tests and linters
43
- "black == 24.10.0",
44
- "flake8 == 7.1.1",
45
- "pytest == 8.3.3",
46
- "mypy == 1.13.0",
43
+ "black == 25.1.0",
44
+ "flake8 == 7.1.2",
45
+ "pytest == 8.3.5",
46
+ "mypy == 1.15.0",
47
47
 
48
48
  # Managing source distributions
49
49
  "build == 1.2.2",
50
- "twine == 5.1.1",
50
+ "twine == 6.1.0",
51
51
  ]
52
52
  docs = [
53
- "Sphinx == 8.1.3",
53
+ "Sphinx == 8.2.3",
54
54
  "furo == 2024.8.6",
55
55
  "numpydoc == 1.8.0",
56
56
  "sphinx-copybutton == 0.5.2",
@@ -4,7 +4,8 @@ import logging
4
4
  import time
5
5
  import traceback
6
6
  from collections import deque
7
- from typing import Any, Iterable
7
+ from collections.abc import Iterable
8
+ from typing import Any
8
9
 
9
10
  from .graph import AsyncGraph, InvalidAsyncGraphError
10
11
 
@@ -284,7 +285,10 @@ class AsyncExecutor:
284
285
  self._exceptions = {}
285
286
 
286
287
  for node_name, node in self._graph._nodes.items():
287
- queue = asyncio.Queue(maxsize=node.queue_size)
288
+ if node.queue is None:
289
+ queue = asyncio.Queue(maxsize=node.queue_size)
290
+ else:
291
+ queue = node.queue
288
292
  self._node_queues[node_name] = queue
289
293
  self._data_flow_stats[node_name] = {"in": 0, "out": 0, "err": 0}
290
294
  self._exceptions[node_name] = deque(maxlen=self._max_exceptions)
@@ -1,6 +1,8 @@
1
+ import asyncio
1
2
  import inspect
2
3
  from collections import OrderedDict
3
- from typing import Any, Callable, NamedTuple
4
+ from collections.abc import AsyncGenerator, Callable
5
+ from typing import Any, NamedTuple
4
6
 
5
7
 
6
8
  class InvalidAsyncGraphError(Exception):
@@ -8,8 +10,9 @@ class InvalidAsyncGraphError(Exception):
8
10
 
9
11
 
10
12
  class _Node(NamedTuple):
11
- func: Callable
13
+ func: Callable[..., AsyncGenerator]
12
14
  name: str
15
+ queue: asyncio.Queue | None
13
16
  queue_size: int
14
17
  max_tasks: int
15
18
  halt_on_exception: bool
@@ -32,12 +35,13 @@ class AsyncGraph:
32
35
 
33
36
  def add_node(
34
37
  self,
35
- func: Callable,
38
+ func: Callable[..., AsyncGenerator],
36
39
  *,
37
40
  name: str | None = None,
38
41
  halt_on_exception: bool = False,
39
42
  unpack_input: bool = True,
40
43
  max_tasks: int = 1,
44
+ queue: asyncio.Queue | None = None,
41
45
  queue_size: int = 10_000,
42
46
  check_async_gen: bool = True,
43
47
  ) -> None:
@@ -45,8 +49,8 @@ class AsyncGraph:
45
49
 
46
50
  Parameters
47
51
  ----------
48
- func : Callable
49
- The function that this node runs.
52
+ func : Callable[..., AsyncGenerator]
53
+ The asynchronous generator function that this node runs.
50
54
  See notes below for the function's requirements.
51
55
  name : str, optional
52
56
  The name of this node. If not provided, the ``__name__`` attribute
@@ -62,10 +66,23 @@ class AsyncGraph:
62
66
  See notes below for more details.
63
67
  max_tasks : int, optional
64
68
  The number of tasks that this node runs concurrently.
69
+ queue : asyncio.Queue, optional
70
+ The queue object that collects items from this node's source nodes,
71
+ via ``await queue.put(item)``, and then feed into this node
72
+ with items retrieved by ``await queue.get()``.
73
+ This queue object must be an instance of either :class:`~asyncio.Queue` or
74
+ a subclass of :class:`~asyncio.Queue`.
75
+ If ``None`` or not given, it defaults to an ``asyncio.Queue()`` with max
76
+ size set by ``queue_size``.
65
77
  queue_size : int, optional
66
78
  The maximum number of data items allowed to be
67
- in the :class:`~asyncio.Queue` object between this node as a source
68
- and its destination node(s).
79
+ in the queue object between this node as a destination node
80
+ and its source node(s).
81
+
82
+ .. deprecated:: 1.6.0
83
+ The argument ``queue_size`` is deprecated and will be removed in
84
+ v2.0.0. To configure the queue size, please use the argument ``queue``
85
+ for a queue object whose queue size is set.
69
86
  check_async_gen : bool, optional
70
87
  If ``True`` (the default), the callable ``func`` is verified to be an async
71
88
  generator function by :func:`inspect.isasyncgenfunction`.
@@ -129,9 +146,12 @@ class AsyncGraph:
129
146
  raise TypeError(f"node '{name}' isn't an async generator function")
130
147
  if name in self._nodes:
131
148
  raise ValueError(f"node '{name}' already exists in the graph")
149
+ if queue is not None and not isinstance(queue, asyncio.Queue):
150
+ raise TypeError(f"queue must be an instance of asyncio.Queue: {queue}")
132
151
  self._nodes[name] = _Node(
133
152
  func=func,
134
153
  name=name,
154
+ queue=queue,
135
155
  queue_size=queue_size,
136
156
  max_tasks=max_tasks,
137
157
  halt_on_exception=halt_on_exception,
@@ -139,14 +159,18 @@ class AsyncGraph:
139
159
  )
140
160
  self._nodes_to_edges[name] = set()
141
161
 
142
- def add_edge(self, src_node: str | Callable, dst_node: str | Callable) -> None:
162
+ def add_edge(
163
+ self,
164
+ src_node: str | Callable[..., AsyncGenerator],
165
+ dst_node: str | Callable[..., AsyncGenerator],
166
+ ) -> None:
143
167
  """Add an edge.
144
168
 
145
169
  Parameters
146
170
  ----------
147
- src_node : str | Callable
171
+ src_node : str | Callable[..., AsyncGenerator]
148
172
  The source node, either the function name or the function itself.
149
- dst_node : str | Callable
173
+ dst_node : str | Callable[..., AsyncGenerator]
150
174
  The destination node, either the function name or the function itself.
151
175
  """
152
176
  if not isinstance(src_node, str):
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: async-graph-data-flow
3
- Version: 1.5.1
3
+ Version: 1.6.0
4
4
  Summary: Asynchronous functions that pass data along a directed acyclic graph
5
5
  Author-email: Civis Analytics <opensource@civisanalytics.com>
6
6
  License: BSD 3-Clause
@@ -24,14 +24,14 @@ Requires-Python: >=3.10
24
24
  Description-Content-Type: text/markdown
25
25
  License-File: LICENSE.txt
26
26
  Provides-Extra: dev
27
- Requires-Dist: black==24.10.0; extra == "dev"
28
- Requires-Dist: flake8==7.1.1; extra == "dev"
29
- Requires-Dist: pytest==8.3.3; extra == "dev"
30
- Requires-Dist: mypy==1.13.0; extra == "dev"
27
+ Requires-Dist: black==25.1.0; extra == "dev"
28
+ Requires-Dist: flake8==7.1.2; extra == "dev"
29
+ Requires-Dist: pytest==8.3.5; extra == "dev"
30
+ Requires-Dist: mypy==1.15.0; extra == "dev"
31
31
  Requires-Dist: build==1.2.2; extra == "dev"
32
- Requires-Dist: twine==5.1.1; extra == "dev"
32
+ Requires-Dist: twine==6.1.0; extra == "dev"
33
33
  Provides-Extra: docs
34
- Requires-Dist: Sphinx==8.1.3; extra == "docs"
34
+ Requires-Dist: Sphinx==8.2.3; extra == "docs"
35
35
  Requires-Dist: furo==2024.8.6; extra == "docs"
36
36
  Requires-Dist: numpydoc==1.8.0; extra == "docs"
37
37
  Requires-Dist: sphinx-copybutton==0.5.2; extra == "docs"
@@ -77,7 +77,7 @@ black --check src tests examples
77
77
 
78
78
  ## Building Documentation
79
79
 
80
- We use the Sphinx framework. The documentation source files are in `docs/source/`.
80
+ We use the Sphinx framework. The documentation source files are in `docs/`.
81
81
  These files can be updated as necessary.
82
82
 
83
83
  The public documentation is accessible at https://async-graph-data-flow.readthedocs.io.
@@ -1,14 +1,14 @@
1
1
 
2
2
  [dev]
3
- black==24.10.0
4
- flake8==7.1.1
5
- pytest==8.3.3
6
- mypy==1.13.0
3
+ black==25.1.0
4
+ flake8==7.1.2
5
+ pytest==8.3.5
6
+ mypy==1.15.0
7
7
  build==1.2.2
8
- twine==5.1.1
8
+ twine==6.1.0
9
9
 
10
10
  [docs]
11
- Sphinx==8.1.3
11
+ Sphinx==8.2.3
12
12
  furo==2024.8.6
13
13
  numpydoc==1.8.0
14
14
  sphinx-copybutton==0.5.2
@@ -84,6 +84,7 @@ class TestAsyncGraphAddNode:
84
84
  "halt_on_exception": False,
85
85
  "max_tasks": 1,
86
86
  "name": "extract_node",
87
+ "queue": None,
87
88
  "queue_size": 10_000,
88
89
  "unpack_input": True,
89
90
  },
@@ -92,6 +93,7 @@ class TestAsyncGraphAddNode:
92
93
  "halt_on_exception": False,
93
94
  "max_tasks": 1,
94
95
  "name": "transform_node",
96
+ "queue": None,
95
97
  "queue_size": 10_000,
96
98
  "unpack_input": True,
97
99
  },
@@ -100,6 +102,7 @@ class TestAsyncGraphAddNode:
100
102
  "halt_on_exception": False,
101
103
  "max_tasks": 1,
102
104
  "name": "load_node",
105
+ "queue": None,
103
106
  "queue_size": 10_000,
104
107
  "unpack_input": True,
105
108
  },