computation-graph 53__tar.gz → 56__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 (36) hide show
  1. {computation-graph-53 → computation_graph-56}/PKG-INFO +1 -1
  2. {computation-graph-53 → computation_graph-56}/computation_graph/base_types.py +5 -3
  3. {computation-graph-53 → computation_graph-56}/computation_graph/composers/__init__.py +31 -33
  4. {computation-graph-53 → computation_graph-56}/computation_graph/composers/duplication.py +2 -1
  5. {computation-graph-53 → computation_graph-56}/computation_graph/graph.py +25 -22
  6. {computation-graph-53 → computation_graph-56}/computation_graph/graph_test.py +54 -5
  7. {computation-graph-53 → computation_graph-56}/computation_graph/legacy.py +3 -0
  8. computation_graph-56/computation_graph/run.py +609 -0
  9. {computation-graph-53 → computation_graph-56}/computation_graph/signature.py +7 -10
  10. {computation-graph-53 → computation_graph-56}/computation_graph.egg-info/PKG-INFO +1 -1
  11. {computation-graph-53 → computation_graph-56}/computation_graph.egg-info/top_level.txt +1 -0
  12. {computation-graph-53 → computation_graph-56}/setup.py +1 -1
  13. computation-graph-53/computation_graph/run.py +0 -398
  14. {computation-graph-53 → computation_graph-56}/LICENSE.md +0 -0
  15. {computation-graph-53 → computation_graph-56}/README.md +0 -0
  16. {computation-graph-53 → computation_graph-56}/computation_graph/__init__.py +0 -0
  17. {computation-graph-53 → computation_graph-56}/computation_graph/composers/composers_test.py +0 -0
  18. {computation-graph-53 → computation_graph-56}/computation_graph/composers/condition.py +0 -0
  19. {computation-graph-53 → computation_graph-56}/computation_graph/composers/condition_test.py +0 -0
  20. {computation-graph-53 → computation_graph-56}/computation_graph/composers/debug.py +0 -0
  21. {computation-graph-53 → computation_graph-56}/computation_graph/composers/lift.py +0 -0
  22. {computation-graph-53 → computation_graph-56}/computation_graph/composers/logic.py +0 -0
  23. {computation-graph-53 → computation_graph-56}/computation_graph/composers/memory.py +0 -0
  24. {computation-graph-53 → computation_graph-56}/computation_graph/composers/memory_test.py +0 -0
  25. {computation-graph-53 → computation_graph-56}/computation_graph/graph_runners.py +0 -0
  26. {computation-graph-53 → computation_graph-56}/computation_graph/trace/__init__.py +0 -0
  27. {computation-graph-53 → computation_graph-56}/computation_graph/trace/ascii.py +0 -0
  28. {computation-graph-53 → computation_graph-56}/computation_graph/trace/graphviz.py +0 -0
  29. {computation-graph-53 → computation_graph-56}/computation_graph/trace/graphviz_test.py +0 -0
  30. {computation-graph-53 → computation_graph-56}/computation_graph/trace/mermaid.py +0 -0
  31. {computation-graph-53 → computation_graph-56}/computation_graph/trace/trace_utils.py +0 -0
  32. {computation-graph-53 → computation_graph-56}/computation_graph.egg-info/SOURCES.txt +0 -0
  33. {computation-graph-53 → computation_graph-56}/computation_graph.egg-info/dependency_links.txt +0 -0
  34. {computation-graph-53 → computation_graph-56}/computation_graph.egg-info/requires.txt +0 -0
  35. {computation-graph-53 → computation_graph-56}/pyproject.toml +0 -0
  36. {computation-graph-53 → computation_graph-56}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: computation-graph
3
- Version: 53
3
+ Version: 56
4
4
  Requires-Python: >=3
5
5
  Description-Content-Type: text/markdown
6
6
  License-File: LICENSE.md
@@ -96,11 +96,13 @@ class ComputationNode:
96
96
  func: Callable
97
97
  signature: NodeSignature
98
98
  is_terminal: bool
99
+ computed_hash: int = dataclasses.field(init=False)
100
+
101
+ def __post_init__(self):
102
+ object.__setattr__(self, "computed_hash", hash(self.func))
99
103
 
100
104
  def __hash__(self):
101
- if self.is_terminal:
102
- return hash(self.name)
103
- return hash(self.func)
105
+ return self.computed_hash
104
106
 
105
107
  def __repr__(self):
106
108
  return self.name
@@ -48,14 +48,14 @@ def make_and(
48
48
 
49
49
  merge_node = graph.make_computation_node(args_to_tuple)
50
50
 
51
- return gamla.pipe(
51
+ return gamla.sync.pipe(
52
52
  funcs,
53
- gamla.map(_callable_or_graph_type_to_node_or_graph_type),
53
+ gamla.sync.map(_callable_or_graph_type_to_node_or_graph_type),
54
54
  tuple,
55
- gamla.juxtcat(
56
- gamla.map(_get_edges_from_node_or_graph),
57
- gamla.compose_left(
58
- gamla.map(_infer_sink),
55
+ gamla.sync.juxtcat(
56
+ gamla.sync.map(_get_edges_from_node_or_graph),
57
+ gamla.sync.compose_left(
58
+ gamla.sync.map(_infer_sink),
59
59
  tuple,
60
60
  lambda nodes: (
61
61
  (
@@ -72,7 +72,7 @@ def make_and(
72
72
  ),
73
73
  ),
74
74
  ),
75
- gamla.star(base_types.merge_graphs),
75
+ gamla.sync.star(base_types.merge_graphs),
76
76
  )
77
77
 
78
78
 
@@ -92,13 +92,13 @@ def make_or(
92
92
 
93
93
  filter_node = graph.make_computation_node(filter_computation_errors)
94
94
 
95
- return gamla.pipe(
95
+ return gamla.sync.pipe(
96
96
  funcs,
97
- gamla.map(make_optional(default_value=_ComputationError())),
97
+ gamla.sync.map(make_optional(default_value=_ComputationError())),
98
98
  tuple,
99
- gamla.pair_with(
100
- gamla.compose_left(
101
- gamla.map(_infer_sink),
99
+ gamla.sync.pair_right(
100
+ gamla.sync.compose_left(
101
+ gamla.sync.map(_infer_sink),
102
102
  tuple,
103
103
  lambda sinks: (
104
104
  (
@@ -116,7 +116,7 @@ def make_or(
116
116
  )
117
117
  ),
118
118
  gamla.concat,
119
- gamla.star(base_types.merge_graphs),
119
+ gamla.sync.star(base_types.merge_graphs),
120
120
  )
121
121
 
122
122
 
@@ -126,18 +126,16 @@ _destinations = gamla.compose(set, gamla.map(base_types.edge_destination))
126
126
  def _infer_sink(graph_or_node: base_types.NodeOrGraph) -> base_types.ComputationNode:
127
127
  if isinstance(graph_or_node, base_types.ComputationNode):
128
128
  return graph_or_node
129
- graph_without_future_edges = gamla.pipe(graph_or_node, graph.remove_future_edges)
129
+ graph_without_future_edges = graph.remove_future_edges(graph_or_node)
130
130
  if graph_without_future_edges:
131
131
  try:
132
- return gamla.pipe(
133
- graph_without_future_edges, graph.sink_excluding_terminals
134
- )
132
+ return graph.sink_excluding_terminals(graph_without_future_edges)
135
133
  except AssertionError:
136
134
  # If we reached here we can try again without sources of future edges.
137
- sources_of_future_edges = gamla.pipe(
135
+ sources_of_future_edges = gamla.sync.pipe(
138
136
  graph_or_node,
139
- gamla.filter(base_types.edge_is_future),
140
- gamla.map(base_types.edge_source),
137
+ gamla.sync.filter(base_types.edge_is_future),
138
+ gamla.sync.map(base_types.edge_source),
141
139
  frozenset,
142
140
  )
143
141
  result = (
@@ -234,30 +232,30 @@ def _infer_composition_edges(
234
232
  graph.get_incoming_edges_for_node(destination)
235
233
  )
236
234
  return base_types.merge_graphs(
237
- gamla.pipe(
235
+ gamla.sync.pipe(
238
236
  destination,
239
- gamla.mapcat(graph.get_edge_nodes),
237
+ gamla.sync.mapcat(graph.get_edge_nodes),
240
238
  gamla.unique,
241
- gamla.filter(
242
- gamla.compose_left(
239
+ gamla.sync.filter(
240
+ gamla.sync.compose_left(
243
241
  unbound_signature,
244
242
  lambda sig: key in sig.kwargs
245
243
  or (key is None and signature.is_unary(sig)),
246
244
  )
247
245
  ),
248
246
  # Do not add edges to nodes from source that are already present in destination (cycle).
249
- gamla.filter(
247
+ gamla.sync.filter(
250
248
  lambda node: isinstance(source, base_types.ComputationNode)
251
249
  or node not in graph.get_all_nodes(source)
252
250
  ),
253
- gamla.map(
251
+ gamla.sync.map(
254
252
  lambda destination: try_connect(
255
253
  destination=destination,
256
254
  unbound_destination_signature=unbound_signature(destination),
257
255
  )
258
256
  ),
259
257
  tuple,
260
- gamla.check(
258
+ gamla.sync.check(
261
259
  gamla.identity,
262
260
  AssertionError(
263
261
  f"Cannot compose, destination signature does not contain key '{key}'"
@@ -278,13 +276,13 @@ def _make_compose_inner(
278
276
  assert (
279
277
  len(funcs) > 1
280
278
  ), f"Only {len(funcs)} function passed to compose, need at least 2, funcs={funcs}"
281
- return gamla.pipe(
279
+ return gamla.sync.pipe(
282
280
  funcs,
283
281
  reversed,
284
- gamla.map(_callable_or_graph_type_to_node_or_graph_type),
282
+ gamla.sync.map(_callable_or_graph_type_to_node_or_graph_type),
285
283
  gamla.sliding_window(2),
286
- gamla.map(gamla.star(_infer_composition_edges(priority, key, is_future))),
287
- gamla.star(base_types.merge_graphs),
284
+ gamla.sync.map(gamla.star(_infer_composition_edges(priority, key, is_future))),
285
+ gamla.sync.star(base_types.merge_graphs),
288
286
  )
289
287
 
290
288
 
@@ -389,8 +387,8 @@ def compose_dict(
389
387
  return gamla.pipe(
390
388
  d,
391
389
  dict.items,
392
- gamla.map(gamla.star(lambda key, fn: make_compose(f, fn, key=key))),
393
- gamla.star(base_types.merge_graphs),
390
+ gamla.sync.map(gamla.star(lambda key, fn: make_compose(f, fn, key=key))),
391
+ gamla.sync.star(base_types.merge_graphs),
394
392
  ) or compose_left_unary(f, lambda x: x)
395
393
 
396
394
 
@@ -44,6 +44,7 @@ _duplicate_node = gamla.compose_left(
44
44
  graph.make_computation_node,
45
45
  )
46
46
 
47
+ duplicate_node = _duplicate_node
47
48
 
48
49
  _node_to_duplicated_node = gamla.compose_left(
49
50
  gamla.remove(base_types.node_is_terminal),
@@ -104,4 +105,4 @@ def safe_replace_sources(
104
105
  g = graph.replace_source(source, get_node_replacement(source), g)
105
106
  return g
106
107
 
107
- return gamla.reduce(lambda updated_cg, e: updated_cg + update_edge(e), (), cg)
108
+ return base_types.merge_graphs(*(update_edge(e) for e in cg))
@@ -6,16 +6,16 @@ from gamla.optimized import sync as opt_gamla
6
6
 
7
7
  from computation_graph import base_types, signature
8
8
 
9
- get_edge_nodes = gamla.ternary(
9
+ get_edge_nodes = opt_gamla.ternary(
10
10
  base_types.edge_args,
11
11
  lambda edge: edge.args + (edge.destination,),
12
12
  lambda edge: (edge.source, edge.destination),
13
13
  )
14
14
 
15
- get_all_nodes = gamla.compose_left(gamla.mapcat(get_edge_nodes), frozenset)
15
+ get_all_nodes = opt_gamla.compose_left(opt_gamla.mapcat(get_edge_nodes), frozenset)
16
16
 
17
17
 
18
- edges_to_node_id_map = gamla.compose_left(
18
+ edges_to_node_id_map = opt_gamla.compose_left(
19
19
  gamla.mapcat(get_edge_nodes), gamla.unique, enumerate, gamla.map(reversed), dict
20
20
  )
21
21
 
@@ -41,13 +41,13 @@ def make_computation_node(
41
41
 
42
42
 
43
43
  def get_leaves(edges: base_types.GraphType) -> FrozenSet[base_types.ComputationNode]:
44
- return gamla.pipe(
44
+ return opt_gamla.pipe(
45
45
  edges,
46
46
  get_all_nodes,
47
- gamla.remove(
48
- gamla.pipe(
47
+ opt_gamla.remove(
48
+ opt_gamla.pipe(
49
49
  edges,
50
- gamla.mapcat(lambda edge: (edge.source, *edge.args)),
50
+ opt_gamla.mapcat(lambda edge: (edge.source, *edge.args)),
51
51
  frozenset,
52
52
  gamla.contains,
53
53
  )
@@ -56,27 +56,29 @@ def get_leaves(edges: base_types.GraphType) -> FrozenSet[base_types.ComputationN
56
56
  )
57
57
 
58
58
 
59
- sink_excluding_terminals = gamla.compose_left(
59
+ sink_excluding_terminals = opt_gamla.compose_left(
60
60
  get_leaves,
61
- gamla.remove(base_types.node_is_terminal),
61
+ opt_gamla.remove(base_types.node_is_terminal),
62
62
  tuple,
63
63
  gamla.assert_that(gamla.len_equals(1)),
64
64
  gamla.head,
65
65
  )
66
66
 
67
- get_incoming_edges_for_node = gamla.compose_left(
68
- gamla.groupby(base_types.edge_destination),
69
- gamla.valmap(frozenset),
67
+ get_incoming_edges_for_node = opt_gamla.compose_left(
68
+ opt_gamla.groupby(base_types.edge_destination),
69
+ opt_gamla.valmap(frozenset),
70
70
  gamla.dict_to_getter_with_default(frozenset()),
71
71
  )
72
72
 
73
73
 
74
- get_terminals = gamla.compose_left(
75
- get_all_nodes, gamla.filter(base_types.node_is_terminal), tuple
74
+ get_terminals = opt_gamla.compose_left(
75
+ get_all_nodes, opt_gamla.filter(base_types.node_is_terminal), tuple
76
76
  )
77
77
 
78
78
 
79
- remove_future_edges = gamla.compose(tuple, opt_gamla.remove(base_types.edge_is_future))
79
+ remove_future_edges = opt_gamla.compose(
80
+ tuple, opt_gamla.remove(base_types.edge_is_future)
81
+ )
80
82
 
81
83
 
82
84
  def make_source():
@@ -98,7 +100,7 @@ def make_terminal(name: str, func: Callable) -> base_types.ComputationNode:
98
100
  )
99
101
 
100
102
 
101
- _keep_not_in_bound_kwargs = gamla.compose_left(
103
+ _keep_not_in_bound_kwargs = opt_gamla.compose_left(
102
104
  opt_gamla.map(base_types.edge_key),
103
105
  gamla.filter(gamla.identity),
104
106
  frozenset,
@@ -151,16 +153,16 @@ def _replace_source_in_edges(
151
153
  traverse_forward: Callable[
152
154
  [base_types.GraphType],
153
155
  Callable[[base_types.CallableOrNode], Tuple[base_types.ComputationNode, ...]],
154
- ] = gamla.compose_left(
156
+ ] = opt_gamla.compose_left(
155
157
  gamla.mapcat(
156
- gamla.compose_left(
158
+ opt_gamla.compose_left(
157
159
  gamla.juxt(base_types.edge_sources, base_types.edge_destination),
158
160
  gamla.explode(0),
159
161
  )
160
162
  ),
161
163
  gamla.groupby_many_reduce(
162
- gamla.compose_left(gamla.head, gamla.wrap_tuple),
163
- lambda destinations, e: (*(destinations if destinations else ()), e[1]),
164
+ opt_gamla.compose_left(gamla.head, gamla.wrap_tuple),
165
+ lambda destinations, e: {*(destinations if destinations else ()), e[1]},
164
166
  ),
165
167
  gamla.dict_to_getter_with_default(()),
166
168
  gamla.before(make_computation_node),
@@ -212,7 +214,8 @@ def transform_edges(
212
214
  edge_mapper: Callable[[base_types.ComputationEdge], base_types.ComputationEdge],
213
215
  ):
214
216
  return _operate_on_subgraph(
215
- _split_by_condition(query), gamla.compose_left(gamla.map(edge_mapper), tuple)
217
+ _split_by_condition(query),
218
+ opt_gamla.compose_left(gamla.map(edge_mapper), tuple),
216
219
  )
217
220
 
218
221
 
@@ -283,7 +286,7 @@ def _operate_on_subgraph(selector, transformation):
283
286
 
284
287
 
285
288
  def _split_by_condition(condition):
286
- return gamla.compose_left(
289
+ return opt_gamla.compose_left(
287
290
  gamla.bifurcate(gamla.filter(condition), gamla.remove(condition)),
288
291
  gamla.map(tuple),
289
292
  tuple,
@@ -63,6 +63,55 @@ def test_simple():
63
63
  )
64
64
 
65
65
 
66
+ async def test_async_run_as_soon_as_possible(capsys):
67
+ # This test is to make sure that the async node runs as soon as possible.
68
+ # nodes in different topological layers should run concurrently if not dependent on each other.
69
+ async def concurrent1(x):
70
+ print("start concurrent1") # noqa
71
+ await asyncio.sleep(0.1)
72
+ print("end concurrent1") # noqa
73
+ return "concurrent1"
74
+
75
+ async def concurrent2(x):
76
+ print("start concurrent2") # noqa
77
+ await asyncio.sleep(0.1)
78
+ print("end concurrent2") # noqa
79
+ return "concurrent2"
80
+
81
+ def sink(x, y):
82
+ return f"x={x}, y={y}"
83
+
84
+ g = base_types.merge_graphs(
85
+ composers.compose_unary(concurrent1, lambda: "x"),
86
+ composers.compose_unary(concurrent2, lambda y: y, lambda: "y"),
87
+ composers.compose_left(concurrent1, sink, key="x"),
88
+ composers.compose_left(concurrent2, sink, key="y"),
89
+ )
90
+
91
+ await graph_runners.nullary(g, sink)
92
+
93
+ # Capture the output
94
+ captured = capsys.readouterr()
95
+
96
+ # Assertions
97
+ assert "start concurrent1" in captured.out
98
+ assert "start concurrent2" in captured.out
99
+ assert "end concurrent1" in captured.out
100
+ assert "end concurrent2" in captured.out
101
+ assert captured.out.index("start concurrent1") < captured.out.index(
102
+ "end concurrent1"
103
+ )
104
+ assert captured.out.index("start concurrent2") < captured.out.index(
105
+ "end concurrent2"
106
+ )
107
+ assert captured.out.index("start concurrent1") < captured.out.index(
108
+ "end concurrent2"
109
+ )
110
+ assert captured.out.index("start concurrent2") < captured.out.index(
111
+ "end concurrent1"
112
+ )
113
+
114
+
66
115
  async def test_simple_async():
67
116
  assert (
68
117
  await graph_runners.unary(
@@ -376,7 +425,7 @@ def test_or_with_sink_that_raises():
376
425
 
377
426
 
378
427
  def test_unambiguous_composition_using_terminal():
379
- terminal = graph.make_terminal("1", lambda x: x)
428
+ terminal = graph.make_terminal("1", lambda x: x[0])
380
429
 
381
430
  def source():
382
431
  return 1
@@ -403,8 +452,8 @@ def test_unambiguous_composition_using_terminal():
403
452
 
404
453
 
405
454
  def test_two_terminals():
406
- terminal1 = graph.make_terminal("1", gamla.wrap_tuple)
407
- terminal2 = graph.make_terminal("2", gamla.wrap_tuple)
455
+ terminal1 = graph.make_terminal("1", lambda x: x)
456
+ terminal2 = graph.make_terminal("2", lambda x: x)
408
457
  result = graph_runners.unary_bare(
409
458
  base_types.merge_graphs(
410
459
  composers.compose_unary(terminal1, composers.make_compose(_node2, _node1)),
@@ -418,8 +467,8 @@ def test_two_terminals():
418
467
 
419
468
  def test_two_paths_succeed():
420
469
  source = graph.make_source()
421
- terminal1 = graph.make_terminal("1", gamla.wrap_tuple)
422
- terminal2 = graph.make_terminal("2", gamla.wrap_tuple)
470
+ terminal1 = graph.make_terminal("1", lambda x: x)
471
+ terminal2 = graph.make_terminal("2", lambda x: x)
423
472
  result = graph_runners.variadic_bare(
424
473
  base_types.merge_graphs(
425
474
  composers.make_first(
@@ -18,6 +18,9 @@ def handle_state(
18
18
  ) -> base_types.GraphType:
19
19
  @graph.make_terminal("retrieve_state")
20
20
  def retrieve_state(x):
21
+ if x == ():
22
+ raise base_types.SkipComputationError
23
+ x = x[0]
21
24
  assert isinstance(x, ComputationResult), x
22
25
  return x.state
23
26