Skip to content

Commit aa7b359

Browse files
committed
Add subgraph and fix GraphNode uid mandatory
1 parent 14b4416 commit aa7b359

5 files changed

Lines changed: 139 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelogs
22

3+
## Version 1.2.0
4+
(Not released yet)
5+
* Add sub_graph
6+
* Fix bug (forced to set an id on GraphNode constructor)
7+
38
## Version 1.1.0
49
(Released : April 16, 2021) : tag 1.1.0
510
* Fix documentation
@@ -25,19 +30,23 @@
2530

2631
## TODO list for FreExGraph (next versions)
2732

33+
## Feature todo
34+
35+
* Implement sub_graph
36+
* ~~fix graph node enforcement of uid~~
37+
* ~~Delete node~~
38+
* ~~Partial graph traversal~~
39+
2840
## Documentation todo
2941

3042
* ~~Add doc about node / graph creation~~
3143
* ~~Add documentation about graph nodes~~
3244
* ~~Add documentation about custom hook~~
3345
* ~~Add documentation Composed Visitor~~
34-
35-
## Feature todo
36-
37-
* ~~Delete node~~
38-
* ~~Partial graph traversal~~
46+
* Add documentation on sub_graph
3947

4048
## Testing todo
4149

50+
* Test sub_graph
4251
* ~~Test Composed Visitor~~
4352
* ~~Custom hook~~

freexgraph/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@
2121
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2222
# SOFTWARE.
2323

24-
__version__ = "1.1.0"
24+
__version__ = "1.2.0"

freexgraph/freexgraph.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,9 @@ class GraphNode(FreExNode):
123123

124124
_graph_ex: "FreExGraph"
125125

126-
def __init__(self, uid: str, *, graph: "FreExGraph", parents: Set[str] = None):
126+
def __init__(
127+
self, uid: str = None, *, graph: "FreExGraph", parents: Set[str] = None
128+
):
127129
super().__init__(uid=uid, parents=parents, graph_ref=graph._graph)
128130
self._graph_ex = graph
129131

@@ -278,6 +280,46 @@ def get_node(self, node_id: str) -> Optional[AnyFreExNode]:
278280
return None
279281
return self._graph.nodes[node_id]["content"]
280282

283+
def sub_graph(
284+
self, from_node_id: str, to_nodes_id: Optional[List[str]] = None
285+
) -> "FreExGraph":
286+
"""Utility method to retrieve a subgraph from a given node until the end of the graph or until one of the
287+
provided node is encountered.
288+
289+
:param from_node_id: node from which the sub graph start
290+
:param to_nodes_id: nodes on which the sub graph stop, if none encountered, subgraph go until the leaf nodes
291+
:return: a sub graph delimited by the provided nodes id
292+
"""
293+
from_node: FreExNode = self.get_node(from_node_id)
294+
assert (
295+
from_node is not None
296+
), f"Error sub graph from node {from_node_id}, node has to be in the execution graph"
297+
298+
nodes_in_subgraph: List[FreExNode] = []
299+
nodes_in_subgraph_id: List[str] = []
300+
301+
def add_node_in_subgraph(current_node: FreExNode):
302+
current_node.parents = {
303+
p for p in current_node.parents if p in nodes_in_subgraph_id
304+
}
305+
nodes_in_subgraph.append(current_node)
306+
if to_nodes_id is not None and current_node in to_nodes_id:
307+
return
308+
all_suc = list(self._graph.successors(current_node.id))
309+
for successor in all_suc:
310+
n = self.get_node(successor)
311+
assert (
312+
n is not None
313+
), f"Error sub graph to node {n.id}, node has to be in the execution graph"
314+
add_node_in_subgraph(n)
315+
nodes_in_subgraph_id.append(n.id)
316+
317+
add_node_in_subgraph(from_node)
318+
319+
sub_graph = FreExGraph()
320+
sub_graph.add_nodes(nodes_in_subgraph)
321+
return sub_graph
322+
281323
def fork_from_node(
282324
self, forked_node: FreExNode, *, join_id: Optional[str] = None
283325
) -> None:

recipe.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
python38.pkgs.buildPythonPackage rec {
55
pname = "freexgraph";
6-
version = "1.1.0";
6+
version = "1.2.0";
77

88
src = if (builtins.isNull use_revision || use_revision == "") then
99
nix-gitignore.gitignoreSource [ ".git" ] ./.

test/sub_graph_test.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# MIT License
2+
#
3+
# Copyright (c) 2021 Quentin Balland
4+
# Project : https://github.com/FreeYourSoul/FreExGraph
5+
#
6+
# Permission is hereby granted, free of charge, to any person obtaining a copy
7+
# of this software and associated documentation files (the "Software"), to deal
8+
# in the Software without restriction, including without limitation the rights
9+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
# copies of the Software, and to permit persons to whom the Software is
11+
# furnished to do so, subject to the following conditions:
12+
#
13+
# The above copyright notice and this permission notice shall be included in all
14+
# copies or substantial portions of the Software.
15+
#
16+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
# SOFTWARE.
23+
24+
import pytest
25+
26+
from freexgraph import GraphNode, FreExNode, FreExGraph
27+
28+
# Graph used in thoses tests are from valid_complex_graph fixture
29+
#
30+
#
31+
# A B
32+
# / \ / |
33+
# C D E |
34+
# \ \ |
35+
# F .______, G |
36+
# / | \ \ / |
37+
# H I J `,K. |
38+
# /,_____/ \ |
39+
# L M
40+
#
41+
42+
43+
def test_sub_graph_without_to_node(valid_complex_graph, visitor_test):
44+
# From F to end
45+
#
46+
# F .______,
47+
# / | \ \
48+
# H I J `,K.
49+
# /,_____/ \
50+
# L M
51+
52+
sub_graph: FreExGraph = valid_complex_graph.sub_graph(from_node_id="F")
53+
54+
visitor_test.visit(valid_complex_graph)
55+
visitor_test.visit(sub_graph.root)
56+
assert len(visitor_test.visited) == 7
57+
58+
59+
def test_sub_graph_of_one_element(valid_complex_graph):
60+
...
61+
62+
63+
def test_sub_graph_with_to_node_not_found(valid_complex_graph):
64+
...
65+
66+
67+
def test_sub_graph_with_to_node(valid_complex_graph):
68+
...
69+
70+
71+
def test_sub_graph_with_to_node_partial(valid_complex_graph):
72+
...
73+
74+
75+
def test_sub_graph_error_on_from_node(valid_complex_graph):
76+
...
77+
78+
79+
def test_sub_graph_error_on_to_node(valid_complex_graph):
80+
...

0 commit comments

Comments
 (0)