computation-graph 69__tar.gz → 70__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 (38) hide show
  1. {computation_graph-69 → computation_graph-70}/PKG-INFO +1 -1
  2. {computation_graph-69 → computation_graph-70}/computation_graph/composers/__init__.py +37 -29
  3. {computation_graph-69 → computation_graph-70}/computation_graph/composers/duplication.py +2 -2
  4. {computation_graph-69 → computation_graph-70}/computation_graph/graph.py +39 -31
  5. {computation_graph-69 → computation_graph-70}/computation_graph/graph_runners.py +2 -2
  6. {computation_graph-69 → computation_graph-70}/computation_graph/run.py +4 -6
  7. {computation_graph-69 → computation_graph-70}/computation_graph/signature.py +1 -36
  8. {computation_graph-69 → computation_graph-70}/computation_graph.egg-info/PKG-INFO +1 -1
  9. {computation_graph-69 → computation_graph-70}/setup.py +1 -1
  10. {computation_graph-69 → computation_graph-70}/LICENSE.md +0 -0
  11. {computation_graph-69 → computation_graph-70}/README.md +0 -0
  12. {computation_graph-69 → computation_graph-70}/computation_graph/__init__.py +0 -0
  13. {computation_graph-69 → computation_graph-70}/computation_graph/base_types.py +0 -0
  14. {computation_graph-69 → computation_graph-70}/computation_graph/composers/composers_test.py +0 -0
  15. {computation_graph-69 → computation_graph-70}/computation_graph/composers/condition.py +0 -0
  16. {computation_graph-69 → computation_graph-70}/computation_graph/composers/condition_test.py +0 -0
  17. {computation_graph-69 → computation_graph-70}/computation_graph/composers/debug.py +0 -0
  18. {computation_graph-69 → computation_graph-70}/computation_graph/composers/lift.py +0 -0
  19. {computation_graph-69 → computation_graph-70}/computation_graph/composers/lift_test.py +0 -0
  20. {computation_graph-69 → computation_graph-70}/computation_graph/composers/logic.py +0 -0
  21. {computation_graph-69 → computation_graph-70}/computation_graph/composers/memory.py +0 -0
  22. {computation_graph-69 → computation_graph-70}/computation_graph/composers/memory_test.py +0 -0
  23. {computation_graph-69 → computation_graph-70}/computation_graph/graph_test.py +0 -0
  24. {computation_graph-69 → computation_graph-70}/computation_graph/infer_sink.py +0 -0
  25. {computation_graph-69 → computation_graph-70}/computation_graph/infer_sink_test.py +0 -0
  26. {computation_graph-69 → computation_graph-70}/computation_graph/legacy.py +0 -0
  27. {computation_graph-69 → computation_graph-70}/computation_graph/trace/__init__.py +0 -0
  28. {computation_graph-69 → computation_graph-70}/computation_graph/trace/ascii.py +0 -0
  29. {computation_graph-69 → computation_graph-70}/computation_graph/trace/graphviz.py +0 -0
  30. {computation_graph-69 → computation_graph-70}/computation_graph/trace/graphviz_test.py +0 -0
  31. {computation_graph-69 → computation_graph-70}/computation_graph/trace/mermaid.py +0 -0
  32. {computation_graph-69 → computation_graph-70}/computation_graph/trace/trace_utils.py +0 -0
  33. {computation_graph-69 → computation_graph-70}/computation_graph.egg-info/SOURCES.txt +0 -0
  34. {computation_graph-69 → computation_graph-70}/computation_graph.egg-info/dependency_links.txt +0 -0
  35. {computation_graph-69 → computation_graph-70}/computation_graph.egg-info/requires.txt +0 -0
  36. {computation_graph-69 → computation_graph-70}/computation_graph.egg-info/top_level.txt +0 -0
  37. {computation_graph-69 → computation_graph-70}/pyproject.toml +0 -0
  38. {computation_graph-69 → computation_graph-70}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: computation-graph
3
- Version: 69
3
+ Version: 70
4
4
  Requires-Python: >=3
5
5
  Description-Content-Type: text/markdown
6
6
  License-File: LICENSE.md
@@ -286,36 +286,44 @@ def _infer_composition_edges(
286
286
  unbound_signature = graph.unbound_signature(
287
287
  graph.get_incoming_edges_for_node(destination.edges)
288
288
  )
289
- source_nodes = (
290
- graph.get_all_nodes(source.edges)
291
- if isinstance(source, GraphType)
292
- else frozenset()
293
- )
294
- skip_cycle_check = isinstance(source, base_types.ComputationNode)
295
- new_edges = set()
296
- # The connectable-node set is order-independent (result is a frozenset), so we
297
- # can iterate the cached node set instead of rescanning the edges.
298
- for node in graph.get_all_nodes(destination.edges):
299
- node_signature = unbound_signature(node)
300
- if not (
301
- key in node_signature.kwargs
302
- or (key is None and signature.is_unary(node_signature))
303
- ):
304
- continue
305
- # Do not add edges to nodes from source that are already present in destination (cycle).
306
- if not skip_cycle_check and node in source_nodes:
307
- continue
308
- new_edges.add(
309
- try_connect(destination=node, unbound_destination_signature=node_signature)
310
- )
311
- if not new_edges:
312
- raise AssertionError(
313
- f"Cannot compose, destination signature does not contain key '{key}'"
314
- )
315
289
  return graph.merge_graphs(
316
- # Sink is a placeholder here; `merge_graphs` below sets the real sink
317
- # via `sink_node_or_graph`.
318
- GraphType(frozenset(new_edges), None), # type: ignore[arg-type]
290
+ gamla.sync.pipe(
291
+ destination,
292
+ gamla.attrgetter("edges"),
293
+ gamla.sync.mapcat(graph.get_edge_nodes),
294
+ gamla.unique,
295
+ gamla.sync.filter(
296
+ gamla.sync.compose_left(
297
+ unbound_signature,
298
+ lambda sig: key in sig.kwargs
299
+ or (key is None and signature.is_unary(sig)),
300
+ )
301
+ ),
302
+ # Do not add edges to nodes from source that are already present in destination (cycle).
303
+ gamla.sync.filter(
304
+ lambda node: isinstance(source, base_types.ComputationNode)
305
+ or node
306
+ not in graph.get_all_nodes(
307
+ source.edges if isinstance(source, GraphType) else source
308
+ )
309
+ ),
310
+ gamla.sync.map(
311
+ lambda destination_node: try_connect(
312
+ destination=destination_node,
313
+ unbound_destination_signature=unbound_signature(destination_node),
314
+ )
315
+ ),
316
+ frozenset,
317
+ gamla.sync.check(
318
+ gamla.identity,
319
+ AssertionError(
320
+ f"Cannot compose, destination signature does not contain key '{key}'"
321
+ ),
322
+ ),
323
+ # Sink is a placeholder here; `merge_graphs` below sets the real sink
324
+ # via `sink_node_or_graph`.
325
+ lambda edges: GraphType(edges, None), # type: ignore[arg-type]
326
+ ),
319
327
  _get_edges_from_node_or_graph(source),
320
328
  destination,
321
329
  sink_node_or_graph=_determine_sink(source, destination, is_future),
@@ -1,6 +1,6 @@
1
+ import asyncio
1
2
  import dataclasses
2
3
  import functools
3
- import inspect
4
4
  from typing import Dict
5
5
 
6
6
  import gamla
@@ -10,7 +10,7 @@ from computation_graph.composers import debug
10
10
 
11
11
 
12
12
  def duplicate_function(func):
13
- if inspect.iscoroutinefunction(func):
13
+ if asyncio.iscoroutinefunction(func):
14
14
 
15
15
  @functools.wraps(func)
16
16
  async def inner(*args, **kwargs):
@@ -1,6 +1,6 @@
1
1
  import dataclasses
2
2
  import functools
3
- from typing import Callable, Dict, FrozenSet, Iterable, Optional, Tuple
3
+ from typing import Callable, Dict, FrozenSet, Optional, Tuple
4
4
 
5
5
  import gamla
6
6
  from gamla.optimized import sync as opt_gamla
@@ -64,17 +64,11 @@ def make_computation_node(
64
64
  )
65
65
 
66
66
 
67
- _EMPTY_EDGE_SET: FrozenSet[base_types.ComputationEdge] = frozenset()
68
-
69
-
70
- def get_incoming_edges_for_node(
71
- edges: Iterable[base_types.ComputationEdge],
72
- ) -> Callable[[base_types.ComputationNode], FrozenSet[base_types.ComputationEdge]]:
73
- grouped: Dict[base_types.ComputationNode, list] = {}
74
- for edge in edges:
75
- grouped.setdefault(edge.destination, []).append(edge)
76
- node_to_edges = {node: frozenset(group) for node, group in grouped.items()}
77
- return lambda node: node_to_edges.get(node, _EMPTY_EDGE_SET)
67
+ get_incoming_edges_for_node = opt_gamla.compose_left(
68
+ opt_gamla.groupby(base_types.edge_destination),
69
+ opt_gamla.valmap(frozenset),
70
+ gamla.dict_to_getter_with_default(frozenset()),
71
+ )
78
72
 
79
73
 
80
74
  get_terminals = opt_gamla.compose_left(
@@ -101,24 +95,30 @@ def make_terminal(name: str, func: Callable) -> base_types.ComputationNode:
101
95
  )
102
96
 
103
97
 
98
+ _keep_not_in_bound_kwargs = opt_gamla.compose_left(
99
+ opt_gamla.map(base_types.edge_key),
100
+ gamla.filter(gamla.identity),
101
+ frozenset,
102
+ gamla.contains,
103
+ gamla.remove,
104
+ )
105
+
106
+
104
107
  @gamla.curry
105
108
  def unbound_signature(
106
109
  node_to_incoming_edges, node: base_types.ComputationNode
107
110
  ) -> base_types.NodeSignature:
108
111
  """Computes the new signature of unbound variables after considering internal edges."""
109
112
  incoming_edges = node_to_incoming_edges(node)
110
- bound_keys = {edge.key for edge in incoming_edges if edge.key}
111
- node_signature = node.signature
113
+ keep_not_in_bound_kwargs = _keep_not_in_bound_kwargs(incoming_edges)
112
114
  return base_types.NodeSignature(
113
- is_kwargs=node_signature.is_kwargs
114
- and all(edge.key != "**kwargs" for edge in incoming_edges)
115
- and signature.is_unary(node_signature),
116
- is_args=node_signature.is_args
115
+ is_kwargs=node.signature.is_kwargs
116
+ and "**kwargs" not in tuple(opt_gamla.map(base_types.edge_key)(incoming_edges))
117
+ and signature.is_unary(node.signature),
118
+ is_args=node.signature.is_args
117
119
  and not any(edge.args for edge in incoming_edges),
118
- kwargs=tuple(k for k in node_signature.kwargs if k not in bound_keys),
119
- optional_kwargs=tuple(
120
- k for k in node_signature.optional_kwargs if k not in bound_keys
121
- ),
120
+ kwargs=tuple(keep_not_in_bound_kwargs(node.signature.kwargs)),
121
+ optional_kwargs=tuple(keep_not_in_bound_kwargs(node.signature.optional_kwargs)),
122
122
  )
123
123
 
124
124
 
@@ -361,20 +361,28 @@ def merge_graphs(
361
361
  isinstance(x, base_types.GraphType) for x in graphs
362
362
  ), f"{graphs} not a graph"
363
363
  assert (
364
- not isinstance(sink_node_or_graph, base_types.GraphType)
365
- or not sink_node_or_graph.edges
364
+ not base_types.is_computation_graph(sink_node_or_graph)
366
365
  or sink_node_or_graph in graphs
367
366
  ), "sink graph must be one of the graphs being merged"
368
367
 
369
- new_g = base_types.GraphType(
370
- base_types.merge_edges(
371
- *(g.edges for g in graphs if g != base_types.EMPTY_GRAPH)
368
+ new_g = gamla.pipe(
369
+ graphs,
370
+ gamla.remove(gamla.equals(base_types.EMPTY_GRAPH)),
371
+ tuple,
372
+ gamla.pair_right(
373
+ gamla.just(
374
+ sink_node_or_graph.sink
375
+ if isinstance(sink_node_or_graph, base_types.GraphType)
376
+ else sink_node_or_graph
377
+ )
372
378
  ),
373
- (
374
- sink_node_or_graph.sink
375
- if isinstance(sink_node_or_graph, base_types.GraphType)
376
- else sink_node_or_graph
379
+ gamla.packstack(
380
+ gamla.compose_left(
381
+ gamla.map(gamla.attrgetter("edges")), gamla.star(base_types.merge_edges)
382
+ ),
383
+ gamla.identity,
377
384
  ),
385
+ gamla.star(base_types.GraphType),
378
386
  )
379
387
 
380
388
  if base_types.is_debug_mode():
@@ -1,4 +1,4 @@
1
- import inspect
1
+ import asyncio
2
2
  from typing import Callable, Union
3
3
 
4
4
  import gamla
@@ -77,7 +77,7 @@ def unary_with_state_and_expectations(
77
77
  def variadic_with_state_and_expectations(g, sink):
78
78
  f = run.to_callable_strict(g)
79
79
 
80
- if inspect.iscoroutinefunction(f):
80
+ if asyncio.iscoroutinefunction(f):
81
81
 
82
82
  async def inner(turns):
83
83
  prev = {}
@@ -109,7 +109,7 @@ _is_graph_async = opt_gamla.compose_left(
109
109
  opt_gamla.mapcat(lambda edge: (edge.source, *edge.args)),
110
110
  opt_gamla.remove(gamla.equals(None)),
111
111
  opt_gamla.map(base_types.node_implementation),
112
- gamla.anymap(inspect.iscoroutinefunction),
112
+ gamla.anymap(asyncio.iscoroutinefunction),
113
113
  )
114
114
 
115
115
 
@@ -452,7 +452,7 @@ def _make_get_node_executor(
452
452
  return result
453
453
 
454
454
  all_nodes = graph.get_all_nodes(edges)
455
- async_nodes = {n for n in all_nodes if inspect.iscoroutinefunction(n.func)}
455
+ async_nodes = {n for n in all_nodes if asyncio.iscoroutinefunction(n.func)}
456
456
  sync = all_nodes - async_nodes
457
457
  tf = graph.traverse_forward(edges)
458
458
  downstream_from_async = set(gamla.graph_traverse_many(async_nodes, tf))
@@ -572,9 +572,7 @@ to_callable = to_callable_with_side_effect(gamla.just(gamla.just(None)))
572
572
 
573
573
 
574
574
  def _node_is_properly_composed(
575
- node_to_incoming_edges: Callable[
576
- [base_types.ComputationNode], FrozenSet[base_types.ComputationEdge]
577
- ]
575
+ node_to_incoming_edges: base_types.GraphType,
578
576
  ) -> Callable[[base_types.ComputationNode], bool]:
579
577
  return gamla.compose_left(
580
578
  graph.unbound_signature(node_to_incoming_edges),
@@ -583,7 +581,7 @@ def _node_is_properly_composed(
583
581
  )
584
582
 
585
583
 
586
- def _assert_composition_is_valid(g: typing.Iterable[base_types.ComputationEdge]):
584
+ def _assert_composition_is_valid(g: base_types.GraphType):
587
585
  return opt_gamla.pipe(
588
586
  g,
589
587
  graph.get_all_nodes,
@@ -1,6 +1,5 @@
1
1
  import functools
2
2
  import inspect
3
- import types
4
3
  from types import MappingProxyType
5
4
  from typing import Callable, FrozenSet
6
5
 
@@ -40,7 +39,7 @@ _func_parameters = gamla.compose_left(
40
39
  )
41
40
 
42
41
 
43
- def _from_callable_via_inspect(func: Callable) -> base_types.NodeSignature:
42
+ def from_callable(func: Callable) -> base_types.NodeSignature:
44
43
  function_parameters = _func_parameters(func)
45
44
  return base_types.NodeSignature(
46
45
  is_args=gamla.anymap(parameter_is_star)(function_parameters),
@@ -61,40 +60,6 @@ def _from_callable_via_inspect(func: Callable) -> base_types.NodeSignature:
61
60
  )
62
61
 
63
62
 
64
- def _as_plain_function(func: Callable):
65
- """The `inspect.signature`-equivalent target when it is a plain function whose
66
- signature is fully described by its code object, else None (wrappers with
67
- `__signature__`, partials, methods, builtins and classes need `inspect`)."""
68
- unwrapped = inspect.unwrap(func, stop=lambda f: hasattr(f, "__signature__"))
69
- if not isinstance(unwrapped, types.FunctionType) or hasattr(
70
- unwrapped, "__signature__"
71
- ):
72
- return None
73
- return unwrapped
74
-
75
-
76
- def from_callable(func: Callable) -> base_types.NodeSignature:
77
- plain_function = _as_plain_function(func)
78
- if plain_function is None:
79
- return _from_callable_via_inspect(func)
80
- code = plain_function.__code__
81
- positional = code.co_varnames[: code.co_argcount]
82
- keyword_only = code.co_varnames[
83
- code.co_argcount : code.co_argcount + code.co_kwonlyargcount
84
- ]
85
- defaults = plain_function.__defaults__ or ()
86
- keyword_defaults = plain_function.__kwdefaults__ or {}
87
- return base_types.NodeSignature(
88
- is_args=bool(code.co_flags & inspect.CO_VARARGS),
89
- is_kwargs=bool(code.co_flags & inspect.CO_VARKEYWORDS),
90
- kwargs=positional + keyword_only,
91
- optional_kwargs=(
92
- positional[len(positional) - len(defaults) :]
93
- + tuple(name for name in keyword_only if name in keyword_defaults)
94
- ),
95
- )
96
-
97
-
98
63
  def parameters(signature: base_types.NodeSignature) -> FrozenSet[str]:
99
64
  return frozenset(
100
65
  {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: computation-graph
3
- Version: 69
3
+ Version: 70
4
4
  Requires-Python: >=3
5
5
  Description-Content-Type: text/markdown
6
6
  License-File: LICENSE.md
@@ -7,7 +7,7 @@ with open("README.md", "r") as fh:
7
7
  setuptools.setup(
8
8
  name="computation-graph",
9
9
  python_requires=">=3",
10
- version="69",
10
+ version="70",
11
11
  long_description=_LONG_DESCRIPTION,
12
12
  long_description_content_type="text/markdown",
13
13
  packages=setuptools.find_namespace_packages(),
File without changes
File without changes