computation-graph 63__tar.gz → 65__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-63 → computation_graph-65}/PKG-INFO +8 -2
  2. {computation_graph-63 → computation_graph-65}/computation_graph/base_types.py +11 -11
  3. {computation_graph-63 → computation_graph-65}/computation_graph/composers/__init__.py +3 -3
  4. {computation_graph-63 → computation_graph-65}/computation_graph/composers/duplication.py +2 -2
  5. {computation_graph-63 → computation_graph-65}/computation_graph/composers/lift.py +9 -1
  6. computation_graph-65/computation_graph/composers/lift_test.py +42 -0
  7. {computation_graph-63 → computation_graph-65}/computation_graph/graph.py +14 -20
  8. {computation_graph-63 → computation_graph-65}/computation_graph/graph_test.py +27 -23
  9. {computation_graph-63 → computation_graph-65}/computation_graph.egg-info/PKG-INFO +8 -2
  10. {computation_graph-63 → computation_graph-65}/computation_graph.egg-info/SOURCES.txt +1 -0
  11. {computation_graph-63 → computation_graph-65}/setup.py +1 -1
  12. {computation_graph-63 → computation_graph-65}/LICENSE.md +0 -0
  13. {computation_graph-63 → computation_graph-65}/README.md +0 -0
  14. {computation_graph-63 → computation_graph-65}/computation_graph/__init__.py +0 -0
  15. {computation_graph-63 → computation_graph-65}/computation_graph/composers/composers_test.py +0 -0
  16. {computation_graph-63 → computation_graph-65}/computation_graph/composers/condition.py +0 -0
  17. {computation_graph-63 → computation_graph-65}/computation_graph/composers/condition_test.py +0 -0
  18. {computation_graph-63 → computation_graph-65}/computation_graph/composers/debug.py +0 -0
  19. {computation_graph-63 → computation_graph-65}/computation_graph/composers/logic.py +0 -0
  20. {computation_graph-63 → computation_graph-65}/computation_graph/composers/memory.py +0 -0
  21. {computation_graph-63 → computation_graph-65}/computation_graph/composers/memory_test.py +0 -0
  22. {computation_graph-63 → computation_graph-65}/computation_graph/graph_runners.py +0 -0
  23. {computation_graph-63 → computation_graph-65}/computation_graph/legacy.py +0 -0
  24. {computation_graph-63 → computation_graph-65}/computation_graph/run.py +0 -0
  25. {computation_graph-63 → computation_graph-65}/computation_graph/signature.py +0 -0
  26. {computation_graph-63 → computation_graph-65}/computation_graph/trace/__init__.py +0 -0
  27. {computation_graph-63 → computation_graph-65}/computation_graph/trace/ascii.py +0 -0
  28. {computation_graph-63 → computation_graph-65}/computation_graph/trace/graphviz.py +0 -0
  29. {computation_graph-63 → computation_graph-65}/computation_graph/trace/graphviz_test.py +0 -0
  30. {computation_graph-63 → computation_graph-65}/computation_graph/trace/mermaid.py +0 -0
  31. {computation_graph-63 → computation_graph-65}/computation_graph/trace/trace_utils.py +0 -0
  32. {computation_graph-63 → computation_graph-65}/computation_graph.egg-info/dependency_links.txt +0 -0
  33. {computation_graph-63 → computation_graph-65}/computation_graph.egg-info/requires.txt +0 -0
  34. {computation_graph-63 → computation_graph-65}/computation_graph.egg-info/top_level.txt +0 -0
  35. {computation_graph-63 → computation_graph-65}/pyproject.toml +0 -0
  36. {computation_graph-63 → computation_graph-65}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: computation-graph
3
- Version: 63
3
+ Version: 65
4
4
  Requires-Python: >=3
5
5
  Description-Content-Type: text/markdown
6
6
  License-File: LICENSE.md
@@ -12,6 +12,12 @@ Requires-Dist: termcolor
12
12
  Provides-Extra: test
13
13
  Requires-Dist: pygraphviz; extra == "test"
14
14
  Requires-Dist: pytest>=5.4.0; extra == "test"
15
+ Dynamic: description
16
+ Dynamic: description-content-type
17
+ Dynamic: license-file
18
+ Dynamic: provides-extra
19
+ Dynamic: requires-dist
20
+ Dynamic: requires-python
15
21
 
16
22
  [![Build Status](https://travis-ci.com/hyroai/computation-graph.svg?branch=master)](https://travis-ci.com/hyroai/computation-graph)
17
23
 
@@ -4,7 +4,7 @@ import dataclasses
4
4
  import functools
5
5
  import os
6
6
  import typing
7
- from typing import Callable, Hashable, Optional, Tuple, Union
7
+ from typing import Callable, FrozenSet, Hashable, Optional, Tuple, Union
8
8
 
9
9
  import gamla
10
10
 
@@ -125,7 +125,8 @@ def edge_sources(edge: ComputationEdge) -> Tuple[ComputationNode, ...]:
125
125
 
126
126
  is_computation_graph = gamla.alljuxt(
127
127
  # Note that this cannot be set to `GraphType` (due to `is_instance` limitation).
128
- gamla.is_instance(tuple),
128
+ gamla.is_instance((tuple, set, frozenset)),
129
+ gamla.len_greater(0),
129
130
  gamla.allmap(gamla.is_instance(ComputationEdge)),
130
131
  )
131
132
 
@@ -158,18 +159,17 @@ def _assert_no_unwanted_ambiguity_when_debug_set(graph):
158
159
  assert_no_unwanted_ambiguity(graph)
159
160
 
160
161
 
161
- merge_graphs = gamla.compose_left(
162
- gamla.pack,
163
- gamla.concat,
164
- gamla.unique,
165
- tuple,
166
- _assert_no_unwanted_ambiguity_when_debug_set,
167
- )
162
+ def merge_graphs(*graphs):
163
+ s = frozenset({})
164
+ s = s.union(*graphs)
165
+
166
+ return _assert_no_unwanted_ambiguity_when_debug_set(s)
167
+
168
168
 
169
169
  # We use a tuple to generate a unique id for each node based on the order of edges.
170
- GraphType = Tuple[ComputationEdge, ...]
170
+ GraphType = FrozenSet[ComputationEdge]
171
171
  GraphOrCallable = Union[Callable, GraphType]
172
172
  CallableOrNode = Union[Callable, ComputationNode]
173
173
  CallableOrNodeOrGraph = Union[CallableOrNode, GraphType]
174
174
  NodeOrGraph = Union[ComputationNode, GraphType]
175
- EMPTY_GRAPH = ()
175
+ EMPTY_GRAPH: GraphType = frozenset()
@@ -12,7 +12,7 @@ class _ComputationError:
12
12
 
13
13
 
14
14
  _callable_or_graph_type_to_node_or_graph_type = gamla.unless(
15
- gamla.is_instance(tuple), graph.make_computation_node
15
+ gamla.is_instance((tuple, set, frozenset)), graph.make_computation_node
16
16
  )
17
17
 
18
18
 
@@ -20,7 +20,7 @@ def _get_edges_from_node_or_graph(
20
20
  node_or_graph: base_types.NodeOrGraph,
21
21
  ) -> base_types.GraphType:
22
22
  if isinstance(node_or_graph, base_types.ComputationNode):
23
- return ()
23
+ return base_types.EMPTY_GRAPH
24
24
  return node_or_graph
25
25
 
26
26
 
@@ -145,7 +145,7 @@ def _infer_sink(graph_or_node: base_types.NodeOrGraph) -> base_types.Computation
145
145
  return gamla.head(result)
146
146
 
147
147
  assert len(_destinations(graph_or_node)) == 1, graph_or_node
148
- return base_types.edge_destination(graph_or_node[0])
148
+ return base_types.edge_destination(gamla.head(graph_or_node))
149
149
 
150
150
 
151
151
  def make_first(*graphs: base_types.CallableOrNodeOrGraph) -> base_types.GraphType:
@@ -69,7 +69,7 @@ duplicate_graph = gamla.compose_left(
69
69
  )
70
70
 
71
71
  duplicate_function_or_graph = gamla.ternary(
72
- gamla.is_instance(tuple), duplicate_graph, duplicate_function
72
+ gamla.is_instance((tuple, set, frozenset)), duplicate_graph, duplicate_function
73
73
  )
74
74
 
75
75
 
@@ -100,7 +100,7 @@ def safe_replace_sources(
100
100
 
101
101
  def update_edge(e: base_types.ComputationEdge) -> base_types.GraphType:
102
102
  dest = base_types.edge_destination(e)
103
- g = graph.replace_node(dest, get_node_replacement(dest))((e,))
103
+ g = graph.replace_node(dest, get_node_replacement(dest))(frozenset((e,)))
104
104
  for source in base_types.edge_sources(e):
105
105
  g = graph.replace_source(source, get_node_replacement(source), g)
106
106
  return g
@@ -5,11 +5,19 @@ import gamla
5
5
  from computation_graph import base_types, composers
6
6
 
7
7
 
8
+ def _short_name(x) -> str:
9
+ if x is None or isinstance(x, (int, float, str)):
10
+ return f"{x!s:.30}"
11
+ if isinstance(x, (dict, list, tuple, set, frozenset)):
12
+ return f"{type(x).__name__}[{len(x)}]"
13
+ return type(x).__name__
14
+
15
+
8
16
  def always(x):
9
17
  def always():
10
18
  return x
11
19
 
12
- always.__name__ = f"always {x!s:.30}"
20
+ always.__name__ = f"always {_short_name(x)}"
13
21
  return always
14
22
 
15
23
 
@@ -0,0 +1,42 @@
1
+ from computation_graph.composers import lift
2
+
3
+
4
+ def test_always_returns_the_value():
5
+ assert lift.always(5)() == 5
6
+ obj = {"a": 1}
7
+ assert lift.always(obj)() is obj
8
+
9
+
10
+ def test_always_name_keeps_scalars_readable():
11
+ assert lift.always(5).__name__ == "always 5"
12
+ assert lift.always(3.5).__name__ == "always 3.5"
13
+ assert lift.always("cardiology").__name__ == "always cardiology"
14
+ assert lift.always(None).__name__ == "always None"
15
+
16
+
17
+ def test_always_name_summarizes_containers_by_type_and_length():
18
+ assert lift.always({"a": 1, "b": 2}).__name__ == "always dict[2]"
19
+ assert lift.always([1, 2, 3]).__name__ == "always list[3]"
20
+ assert lift.always((1, 2)).__name__ == "always tuple[2]"
21
+
22
+
23
+ def test_always_name_does_not_render_large_container_contents():
24
+ # The point of the summary: naming a node must not stringify a huge value.
25
+ name = lift.always({i: i for i in range(10_000)}).__name__
26
+ assert name == "always dict[10000]"
27
+
28
+
29
+ def test_always_name_falls_back_to_type_for_other_objects():
30
+ class Custom:
31
+ pass
32
+
33
+ assert lift.always(Custom()).__name__ == "always Custom"
34
+
35
+
36
+ def test_distinct_always_calls_produce_distinct_nodes_despite_equal_names():
37
+ # Names are display-only; node identity is hash(func), and every always()
38
+ # call is a fresh function, so equal names must not collapse two nodes.
39
+ a, b = lift.always({"x": 1}), lift.always({"y": 2})
40
+ assert a.__name__ == b.__name__ == "always dict[1]"
41
+ assert a is not b
42
+ assert hash(a) != hash(b)
@@ -41,28 +41,22 @@ def make_computation_node(
41
41
 
42
42
 
43
43
  def get_leaves(edges: base_types.GraphType) -> FrozenSet[base_types.ComputationNode]:
44
- return opt_gamla.pipe(
45
- edges,
46
- get_all_nodes,
47
- opt_gamla.remove(
48
- opt_gamla.pipe(
49
- edges,
50
- opt_gamla.mapcat(lambda edge: (edge.source, *edge.args)),
51
- frozenset,
52
- gamla.contains,
53
- )
54
- ),
55
- frozenset,
44
+ all_nodes = get_all_nodes(edges)
45
+ all_destinations = frozenset(
46
+ gamla.concat((edge.source, *edge.args) for edge in edges)
56
47
  )
48
+ return all_nodes - all_destinations
57
49
 
58
50
 
59
- sink_excluding_terminals = opt_gamla.compose_left(
60
- get_leaves,
61
- opt_gamla.remove(base_types.node_is_terminal),
62
- tuple,
63
- gamla.assert_that(gamla.len_equals(1)),
64
- gamla.head,
65
- )
51
+ def sink_excluding_terminals(edges: base_types.GraphType) -> base_types.ComputationNode:
52
+ leaves_not_terminal = frozenset(
53
+ node for node in get_leaves(edges) if not node.is_terminal
54
+ )
55
+ assert (
56
+ len(leaves_not_terminal) == 1
57
+ ), f"Expected exactly one non-terminal sink, got {leaves_not_terminal}"
58
+ return gamla.head(leaves_not_terminal)
59
+
66
60
 
67
61
  get_incoming_edges_for_node = opt_gamla.compose_left(
68
62
  opt_gamla.groupby(base_types.edge_destination),
@@ -184,7 +178,7 @@ def replace_source(
184
178
  if base_types.is_computation_graph(replacement):
185
179
  return gamla.pipe(
186
180
  current_graph,
187
- _replace_source_in_edges(original, sink_excluding_terminals(replacement)),
181
+ _replace_source_in_edges(original, sink_excluding_terminals(replacement)), # type: ignore
188
182
  gamla.concat_with(replacement),
189
183
  tuple,
190
184
  )
@@ -834,30 +834,34 @@ def test_replace_source_with_args():
834
834
  key="args",
835
835
  ),
836
836
  )
837
- ) == (
838
- base_types.ComputationEdge(
839
- is_future=False,
840
- priority=0,
841
- source=None,
842
- args=(
843
- graph.make_computation_node(_node1_async),
844
- graph.make_computation_node(_node2),
837
+ ) == frozenset(
838
+ (
839
+ base_types.ComputationEdge(
840
+ is_future=False,
841
+ priority=0,
842
+ source=None,
843
+ args=(
844
+ graph.make_computation_node(_node1_async),
845
+ graph.make_computation_node(_node2),
846
+ ),
847
+ destination=graph.make_computation_node(_merger),
848
+ key="args",
845
849
  ),
846
- destination=graph.make_computation_node(_merger),
847
- key="args",
848
- ),
850
+ )
849
851
  )
850
852
 
851
853
 
852
854
  def test_replace_source_with_graph():
853
855
  a = graph.make_source()
854
856
 
855
- assert graph.replace_source(
856
- _node1, composers.compose_left_unary(_node1_async, _next_int)
857
- )(
858
- base_types.merge_graphs(
859
- composers.compose_source_unary(_node1, a),
860
- composers.compose_left_unary(_node1, _node2),
857
+ assert frozenset(
858
+ graph.replace_source(
859
+ _node1, composers.compose_left_unary(_node1_async, _next_int)
860
+ )(
861
+ base_types.merge_graphs(
862
+ composers.compose_source_unary(_node1, a),
863
+ composers.compose_left_unary(_node1, _node2),
864
+ )
861
865
  )
862
866
  ) == base_types.merge_graphs(
863
867
  composers.compose_source_unary(_node1, a),
@@ -970,12 +974,12 @@ def kuku():
970
974
 
971
975
  t = graph.make_terminal("t", lambda x: x)
972
976
 
973
- g = (
974
- composers.compose_left(a, c)
975
- + composers.compose_left(c, d, key="x")
976
- + composers.compose_left(b, d, key="y")
977
- + composers.compose_left_future(d, b, "x", "bla")
978
- + composers.compose_left(a, t)
977
+ g = base_types.merge_graphs(
978
+ composers.compose_left(a, c),
979
+ composers.compose_left(c, d, key="x"),
980
+ composers.compose_left(b, d, key="y"),
981
+ composers.compose_left_future(d, b, "x", "bla"),
982
+ composers.compose_left(a, t),
979
983
  )
980
984
 
981
985
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: computation-graph
3
- Version: 63
3
+ Version: 65
4
4
  Requires-Python: >=3
5
5
  Description-Content-Type: text/markdown
6
6
  License-File: LICENSE.md
@@ -12,6 +12,12 @@ Requires-Dist: termcolor
12
12
  Provides-Extra: test
13
13
  Requires-Dist: pygraphviz; extra == "test"
14
14
  Requires-Dist: pytest>=5.4.0; extra == "test"
15
+ Dynamic: description
16
+ Dynamic: description-content-type
17
+ Dynamic: license-file
18
+ Dynamic: provides-extra
19
+ Dynamic: requires-dist
20
+ Dynamic: requires-python
15
21
 
16
22
  [![Build Status](https://travis-ci.com/hyroai/computation-graph.svg?branch=master)](https://travis-ci.com/hyroai/computation-graph)
17
23
 
@@ -22,6 +22,7 @@ computation_graph/composers/condition_test.py
22
22
  computation_graph/composers/debug.py
23
23
  computation_graph/composers/duplication.py
24
24
  computation_graph/composers/lift.py
25
+ computation_graph/composers/lift_test.py
25
26
  computation_graph/composers/logic.py
26
27
  computation_graph/composers/memory.py
27
28
  computation_graph/composers/memory_test.py
@@ -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="63",
10
+ version="65",
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