async-graph-data-flow 1.5.0__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.
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/CHANGELOG.md +21 -0
- {async_graph_data_flow-1.5.0/src/async_graph_data_flow.egg-info → async_graph_data_flow-1.6.0}/PKG-INFO +9 -8
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/README.md +1 -1
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/pyproject.toml +7 -6
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow/executor.py +39 -29
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow/graph.py +34 -13
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0/src/async_graph_data_flow.egg-info}/PKG-INFO +9 -8
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow.egg-info/requires.txt +6 -5
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/tests/test_graph.py +3 -0
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/LICENSE.txt +0 -0
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/MANIFEST.in +0 -0
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/setup.cfg +0 -0
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow/__init__.py +0 -0
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow/py.typed +0 -0
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow.egg-info/SOURCES.txt +0 -0
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow.egg-info/dependency_links.txt +0 -0
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow.egg-info/not-zip-safe +0 -0
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow.egg-info/top_level.txt +0 -0
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/tests/test_executor.py +0 -0
- {async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/tests/test_version_number.py +0 -0
|
@@ -19,6 +19,27 @@ 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
|
+
|
|
35
|
+
## [1.5.1] - 2024-11-07
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
- Added static type checking using mypy. (#12)
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
- Fixed documentation to actually show example code. (#12)
|
|
42
|
+
|
|
22
43
|
## [1.5.0] - 2024-10-30
|
|
23
44
|
|
|
24
45
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: async-graph-data-flow
|
|
3
|
-
Version: 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,13 +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==
|
|
28
|
-
Requires-Dist: flake8==7.1.
|
|
29
|
-
Requires-Dist: pytest==8.3.
|
|
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"
|
|
30
31
|
Requires-Dist: build==1.2.2; extra == "dev"
|
|
31
|
-
Requires-Dist: twine==
|
|
32
|
+
Requires-Dist: twine==6.1.0; extra == "dev"
|
|
32
33
|
Provides-Extra: docs
|
|
33
|
-
Requires-Dist: Sphinx==8.
|
|
34
|
+
Requires-Dist: Sphinx==8.2.3; extra == "docs"
|
|
34
35
|
Requires-Dist: furo==2024.8.6; extra == "docs"
|
|
35
36
|
Requires-Dist: numpydoc==1.8.0; extra == "docs"
|
|
36
37
|
Requires-Dist: sphinx-copybutton==0.5.2; extra == "docs"
|
|
@@ -76,7 +77,7 @@ black --check src tests examples
|
|
|
76
77
|
|
|
77
78
|
## Building Documentation
|
|
78
79
|
|
|
79
|
-
We use the Sphinx framework. The documentation source files are in `docs
|
|
80
|
+
We use the Sphinx framework. The documentation source files are in `docs/`.
|
|
80
81
|
These files can be updated as necessary.
|
|
81
82
|
|
|
82
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
|
|
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.
|
|
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,16 +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 ==
|
|
44
|
-
"flake8 == 7.1.
|
|
45
|
-
"pytest == 8.3.
|
|
43
|
+
"black == 25.1.0",
|
|
44
|
+
"flake8 == 7.1.2",
|
|
45
|
+
"pytest == 8.3.5",
|
|
46
|
+
"mypy == 1.15.0",
|
|
46
47
|
|
|
47
48
|
# Managing source distributions
|
|
48
49
|
"build == 1.2.2",
|
|
49
|
-
"twine ==
|
|
50
|
+
"twine == 6.1.0",
|
|
50
51
|
]
|
|
51
52
|
docs = [
|
|
52
|
-
"Sphinx == 8.
|
|
53
|
+
"Sphinx == 8.2.3",
|
|
53
54
|
"furo == 2024.8.6",
|
|
54
55
|
"numpydoc == 1.8.0",
|
|
55
56
|
"sphinx-copybutton == 0.5.2",
|
{async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow/executor.py
RENAMED
|
@@ -4,7 +4,8 @@ import logging
|
|
|
4
4
|
import time
|
|
5
5
|
import traceback
|
|
6
6
|
from collections import deque
|
|
7
|
-
from
|
|
7
|
+
from collections.abc import Iterable
|
|
8
|
+
from typing import Any
|
|
8
9
|
|
|
9
10
|
from .graph import AsyncGraph, InvalidAsyncGraphError
|
|
10
11
|
|
|
@@ -20,7 +21,7 @@ class AsyncExecutor:
|
|
|
20
21
|
self,
|
|
21
22
|
graph: AsyncGraph,
|
|
22
23
|
*,
|
|
23
|
-
logger: logging.Logger = None,
|
|
24
|
+
logger: logging.Logger | None = None,
|
|
24
25
|
max_exceptions: int = 1_000,
|
|
25
26
|
):
|
|
26
27
|
"""Initialize an executor.
|
|
@@ -41,23 +42,23 @@ class AsyncExecutor:
|
|
|
41
42
|
if not isinstance(self._graph, AsyncGraph):
|
|
42
43
|
raise TypeError(f"{self._graph} must be an AsyncGraph instance")
|
|
43
44
|
|
|
44
|
-
self._node_queues = {}
|
|
45
|
-
self._consumer_tasks = {}
|
|
45
|
+
self._node_queues: dict[str, asyncio.Queue] = {}
|
|
46
|
+
self._consumer_tasks: dict[str, asyncio.Task] = {}
|
|
46
47
|
self._halt_pipeline_execution = False
|
|
47
48
|
self._logger = logger if logger else _LOG
|
|
48
49
|
self._max_exceptions = max_exceptions
|
|
49
50
|
|
|
50
|
-
self._data_flow_stats = None
|
|
51
|
+
self._data_flow_stats: dict[str, dict[str, int]] | None = None
|
|
51
52
|
self._data_flow_logging_lock = asyncio.Lock()
|
|
52
53
|
self._data_flow_logging = False
|
|
53
54
|
self._data_flow_logging_node_format = _DEFAULT_DATA_FLOW_LOGGING_NODE_FORMAT
|
|
54
55
|
self._data_flow_logging_time_interval = _DEFAULT_DATA_FLOW_LOGGING_TIME_INTERVAL
|
|
55
|
-
self._data_flow_logging_node_filter = self._graph._nodes.keys()
|
|
56
|
-
self._data_flow_logging_last_timestamp = 0
|
|
56
|
+
self._data_flow_logging_node_filter: Iterable[str] = self._graph._nodes.keys()
|
|
57
|
+
self._data_flow_logging_last_timestamp = 0.0
|
|
57
58
|
|
|
58
|
-
self._start_node_args = None
|
|
59
|
+
self._start_node_args: dict[str, tuple] | None = None
|
|
59
60
|
|
|
60
|
-
self._exceptions = None
|
|
61
|
+
self._exceptions: dict[str, deque[Exception]] | None = None
|
|
61
62
|
|
|
62
63
|
@property
|
|
63
64
|
def graph(self) -> AsyncGraph:
|
|
@@ -72,7 +73,7 @@ class AsyncExecutor:
|
|
|
72
73
|
raised from the node.
|
|
73
74
|
"""
|
|
74
75
|
if self._exceptions is None:
|
|
75
|
-
return
|
|
76
|
+
return None
|
|
76
77
|
from_deque_to_list = {}
|
|
77
78
|
for node_name, excs in self._exceptions.items():
|
|
78
79
|
# `excs` is a deque. Turning it into a list for user-friendliness.
|
|
@@ -152,7 +153,7 @@ class AsyncExecutor:
|
|
|
152
153
|
"""Turn off data flow logging."""
|
|
153
154
|
self._data_flow_logging = False
|
|
154
155
|
|
|
155
|
-
|
|
156
|
+
def _log_data_flow_nodes(self):
|
|
156
157
|
for node, flow in self._data_flow_stats.items():
|
|
157
158
|
if (
|
|
158
159
|
self._data_flow_logging_node_filter
|
|
@@ -186,7 +187,7 @@ class AsyncExecutor:
|
|
|
186
187
|
current_timestamp - self._data_flow_logging_last_timestamp
|
|
187
188
|
> self._data_flow_logging_time_interval
|
|
188
189
|
):
|
|
189
|
-
|
|
190
|
+
self._log_data_flow_nodes()
|
|
190
191
|
self._data_flow_logging_last_timestamp = current_timestamp
|
|
191
192
|
|
|
192
193
|
queue = self._node_queues[node_name]
|
|
@@ -202,17 +203,17 @@ class AsyncExecutor:
|
|
|
202
203
|
try:
|
|
203
204
|
if len(params) == 0:
|
|
204
205
|
coro = node.func()
|
|
205
|
-
elif node.unpack_input and (
|
|
206
|
-
|
|
207
|
-
):
|
|
208
|
-
coro = node.func(
|
|
206
|
+
elif node.unpack_input and isinstance(data, tuple):
|
|
207
|
+
coro = node.func(*data)
|
|
208
|
+
elif node.unpack_input and isinstance(data, dict):
|
|
209
|
+
coro = node.func(**data)
|
|
209
210
|
else:
|
|
210
211
|
coro = node.func(data)
|
|
211
212
|
except asyncio.CancelledError:
|
|
212
213
|
continue
|
|
213
214
|
except Exception as exc:
|
|
214
|
-
|
|
215
|
-
|
|
215
|
+
self._update_data_flow_error_stats(node_name)
|
|
216
|
+
self._update_exceptions(node_name, exc)
|
|
216
217
|
self._logger.error(traceback.format_exc())
|
|
217
218
|
if self._graph.halt_on_exception or node.halt_on_exception:
|
|
218
219
|
self._logger.error(
|
|
@@ -238,8 +239,8 @@ class AsyncExecutor:
|
|
|
238
239
|
except asyncio.CancelledError:
|
|
239
240
|
break
|
|
240
241
|
except Exception as exc:
|
|
241
|
-
|
|
242
|
-
|
|
242
|
+
self._update_data_flow_error_stats(node_name)
|
|
243
|
+
self._update_exceptions(node_name, exc)
|
|
243
244
|
self._logger.error(traceback.format_exc())
|
|
244
245
|
if self._graph.halt_on_exception or node.halt_on_exception:
|
|
245
246
|
# close current agen
|
|
@@ -255,30 +256,39 @@ class AsyncExecutor:
|
|
|
255
256
|
continue
|
|
256
257
|
else:
|
|
257
258
|
node_edges = self._graph._nodes_to_edges[node_name]
|
|
258
|
-
|
|
259
|
+
self._update_data_flow_in_out_stats(node_name, node_edges)
|
|
259
260
|
await self._add_to_node_queue(node_edges, next_data_item)
|
|
260
261
|
|
|
261
262
|
queue.task_done()
|
|
262
263
|
except asyncio.CancelledError:
|
|
263
264
|
break
|
|
264
265
|
|
|
265
|
-
|
|
266
|
+
def _update_data_flow_in_out_stats(self, in_node: str, out_nodes: set[str]):
|
|
267
|
+
if self._data_flow_stats is None:
|
|
268
|
+
return None
|
|
266
269
|
self._data_flow_stats[in_node]["out"] += 1
|
|
267
270
|
for node in out_nodes:
|
|
268
271
|
self._data_flow_stats[node]["in"] += 1
|
|
269
272
|
|
|
270
|
-
|
|
273
|
+
def _update_data_flow_error_stats(self, node: str):
|
|
274
|
+
if self._data_flow_stats is None:
|
|
275
|
+
return None
|
|
271
276
|
self._data_flow_stats[node]["err"] += 1
|
|
272
277
|
|
|
273
|
-
|
|
278
|
+
def _update_exceptions(self, node: str, exc: Exception):
|
|
279
|
+
if self._exceptions is None:
|
|
280
|
+
return None
|
|
274
281
|
self._exceptions[node].append(exc)
|
|
275
282
|
|
|
276
283
|
async def _pipeline_execution(self):
|
|
277
|
-
self._data_flow_stats
|
|
278
|
-
self._exceptions
|
|
284
|
+
self._data_flow_stats = {}
|
|
285
|
+
self._exceptions = {}
|
|
279
286
|
|
|
280
287
|
for node_name, node in self._graph._nodes.items():
|
|
281
|
-
queue
|
|
288
|
+
if node.queue is None:
|
|
289
|
+
queue = asyncio.Queue(maxsize=node.queue_size)
|
|
290
|
+
else:
|
|
291
|
+
queue = node.queue
|
|
282
292
|
self._node_queues[node_name] = queue
|
|
283
293
|
self._data_flow_stats[node_name] = {"in": 0, "out": 0, "err": 0}
|
|
284
294
|
self._exceptions[node_name] = deque(maxlen=self._max_exceptions)
|
|
@@ -299,7 +309,7 @@ class AsyncExecutor:
|
|
|
299
309
|
await asyncio.gather(*self._consumer_tasks.values())
|
|
300
310
|
|
|
301
311
|
if self._data_flow_logging:
|
|
302
|
-
|
|
312
|
+
self._log_data_flow_nodes()
|
|
303
313
|
|
|
304
314
|
def _get_start_node_args(self, start_node_args) -> dict[str, tuple]:
|
|
305
315
|
if start_node_args is None:
|
|
@@ -313,7 +323,7 @@ class AsyncExecutor:
|
|
|
313
323
|
raise TypeError(f"args for the node '{node}' isn't a tuple: {args}")
|
|
314
324
|
return start_node_args
|
|
315
325
|
|
|
316
|
-
def execute(self, start_nodes: dict[str, tuple] = None) -> None:
|
|
326
|
+
def execute(self, start_nodes: dict[str, tuple] | None = None) -> None:
|
|
317
327
|
"""Start executing the functions along the graph.
|
|
318
328
|
|
|
319
329
|
Parameters
|
{async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow/graph.py
RENAMED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
import inspect
|
|
2
3
|
from collections import OrderedDict
|
|
3
|
-
from
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
_DEFAULT_NUM_OF_WORKERS = 1
|
|
4
|
+
from collections.abc import AsyncGenerator, Callable
|
|
5
|
+
from typing import Any, NamedTuple
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
class InvalidAsyncGraphError(Exception):
|
|
@@ -11,8 +10,9 @@ class InvalidAsyncGraphError(Exception):
|
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
class _Node(NamedTuple):
|
|
14
|
-
func: Callable
|
|
13
|
+
func: Callable[..., AsyncGenerator]
|
|
15
14
|
name: str
|
|
15
|
+
queue: asyncio.Queue | None
|
|
16
16
|
queue_size: int
|
|
17
17
|
max_tasks: int
|
|
18
18
|
halt_on_exception: bool
|
|
@@ -35,12 +35,13 @@ class AsyncGraph:
|
|
|
35
35
|
|
|
36
36
|
def add_node(
|
|
37
37
|
self,
|
|
38
|
-
func: Callable,
|
|
38
|
+
func: Callable[..., AsyncGenerator],
|
|
39
39
|
*,
|
|
40
40
|
name: str | None = None,
|
|
41
41
|
halt_on_exception: bool = False,
|
|
42
42
|
unpack_input: bool = True,
|
|
43
43
|
max_tasks: int = 1,
|
|
44
|
+
queue: asyncio.Queue | None = None,
|
|
44
45
|
queue_size: int = 10_000,
|
|
45
46
|
check_async_gen: bool = True,
|
|
46
47
|
) -> None:
|
|
@@ -48,8 +49,8 @@ class AsyncGraph:
|
|
|
48
49
|
|
|
49
50
|
Parameters
|
|
50
51
|
----------
|
|
51
|
-
func : Callable
|
|
52
|
-
The function that this node runs.
|
|
52
|
+
func : Callable[..., AsyncGenerator]
|
|
53
|
+
The asynchronous generator function that this node runs.
|
|
53
54
|
See notes below for the function's requirements.
|
|
54
55
|
name : str, optional
|
|
55
56
|
The name of this node. If not provided, the ``__name__`` attribute
|
|
@@ -65,10 +66,23 @@ class AsyncGraph:
|
|
|
65
66
|
See notes below for more details.
|
|
66
67
|
max_tasks : int, optional
|
|
67
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``.
|
|
68
77
|
queue_size : int, optional
|
|
69
78
|
The maximum number of data items allowed to be
|
|
70
|
-
in the
|
|
71
|
-
and its
|
|
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.
|
|
72
86
|
check_async_gen : bool, optional
|
|
73
87
|
If ``True`` (the default), the callable ``func`` is verified to be an async
|
|
74
88
|
generator function by :func:`inspect.isasyncgenfunction`.
|
|
@@ -132,9 +146,12 @@ class AsyncGraph:
|
|
|
132
146
|
raise TypeError(f"node '{name}' isn't an async generator function")
|
|
133
147
|
if name in self._nodes:
|
|
134
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}")
|
|
135
151
|
self._nodes[name] = _Node(
|
|
136
152
|
func=func,
|
|
137
153
|
name=name,
|
|
154
|
+
queue=queue,
|
|
138
155
|
queue_size=queue_size,
|
|
139
156
|
max_tasks=max_tasks,
|
|
140
157
|
halt_on_exception=halt_on_exception,
|
|
@@ -142,14 +159,18 @@ class AsyncGraph:
|
|
|
142
159
|
)
|
|
143
160
|
self._nodes_to_edges[name] = set()
|
|
144
161
|
|
|
145
|
-
def add_edge(
|
|
162
|
+
def add_edge(
|
|
163
|
+
self,
|
|
164
|
+
src_node: str | Callable[..., AsyncGenerator],
|
|
165
|
+
dst_node: str | Callable[..., AsyncGenerator],
|
|
166
|
+
) -> None:
|
|
146
167
|
"""Add an edge.
|
|
147
168
|
|
|
148
169
|
Parameters
|
|
149
170
|
----------
|
|
150
|
-
src_node : str | Callable
|
|
171
|
+
src_node : str | Callable[..., AsyncGenerator]
|
|
151
172
|
The source node, either the function name or the function itself.
|
|
152
|
-
dst_node : str | Callable
|
|
173
|
+
dst_node : str | Callable[..., AsyncGenerator]
|
|
153
174
|
The destination node, either the function name or the function itself.
|
|
154
175
|
"""
|
|
155
176
|
if not isinstance(src_node, str):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: async-graph-data-flow
|
|
3
|
-
Version: 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,13 +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==
|
|
28
|
-
Requires-Dist: flake8==7.1.
|
|
29
|
-
Requires-Dist: pytest==8.3.
|
|
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"
|
|
30
31
|
Requires-Dist: build==1.2.2; extra == "dev"
|
|
31
|
-
Requires-Dist: twine==
|
|
32
|
+
Requires-Dist: twine==6.1.0; extra == "dev"
|
|
32
33
|
Provides-Extra: docs
|
|
33
|
-
Requires-Dist: Sphinx==8.
|
|
34
|
+
Requires-Dist: Sphinx==8.2.3; extra == "docs"
|
|
34
35
|
Requires-Dist: furo==2024.8.6; extra == "docs"
|
|
35
36
|
Requires-Dist: numpydoc==1.8.0; extra == "docs"
|
|
36
37
|
Requires-Dist: sphinx-copybutton==0.5.2; extra == "docs"
|
|
@@ -76,7 +77,7 @@ black --check src tests examples
|
|
|
76
77
|
|
|
77
78
|
## Building Documentation
|
|
78
79
|
|
|
79
|
-
We use the Sphinx framework. The documentation source files are in `docs
|
|
80
|
+
We use the Sphinx framework. The documentation source files are in `docs/`.
|
|
80
81
|
These files can be updated as necessary.
|
|
81
82
|
|
|
82
83
|
The public documentation is accessible at https://async-graph-data-flow.readthedocs.io.
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
|
|
2
2
|
[dev]
|
|
3
|
-
black==
|
|
4
|
-
flake8==7.1.
|
|
5
|
-
pytest==8.3.
|
|
3
|
+
black==25.1.0
|
|
4
|
+
flake8==7.1.2
|
|
5
|
+
pytest==8.3.5
|
|
6
|
+
mypy==1.15.0
|
|
6
7
|
build==1.2.2
|
|
7
|
-
twine==
|
|
8
|
+
twine==6.1.0
|
|
8
9
|
|
|
9
10
|
[docs]
|
|
10
|
-
Sphinx==8.
|
|
11
|
+
Sphinx==8.2.3
|
|
11
12
|
furo==2024.8.6
|
|
12
13
|
numpydoc==1.8.0
|
|
13
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
|
},
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow/__init__.py
RENAMED
|
File without changes
|
{async_graph_data_flow-1.5.0 → async_graph_data_flow-1.6.0}/src/async_graph_data_flow/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|