Repository: PaulSchweizer/flowpipe

Issue:
Delete nodes from graph
`Graph.delete_node(node)` will break all connections of the node and delete the node object

Discussion:
PaulSchweizer: Resolves #116 

Patch:
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..53b14ec
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,20 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: bug
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+If possible, provide an easy to execute code snippet that demonstrates the bug, otherwise please describe how the bug can be reproduced.
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Suggestions for Solution**
+If you have ideas/suggestions on how to fix the bug, please provide them here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..11fc491
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: enhancement
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.gitignore b/.gitignore
index 98858ec..0cc3f96 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@ cover
 .coverage
 .pytest_cache*
 logos/
+venv*
 
 # Sublime
 *.sublime-project
diff --git a/flowpipe/graph.py b/flowpipe/graph.py
index 79dd9a2..3704d83 100644
--- a/flowpipe/graph.py
+++ b/flowpipe/graph.py
@@ -136,6 +136,17 @@ class Graph(object):
             log.warning(
                 'Node "{0}" is already part of this Graph'.format(node.name))
 
+    def delete_node(self, node):
+        """Disconnect all plugs and then delete the node object."""
+        if node in self.nodes:
+            for plug in node.all_inputs().values():
+                for connection in plug.connections:
+                    plug.disconnect(connection)
+            for plug in node.all_outputs().values():
+                for connection in plug.connections:
+                    plug.disconnect(connection)
+            del self.nodes[self.nodes.index(node)]
+
     def add_plug(self, plug, name=None):
         """Promote the given plug this graph.
 
@@ -506,14 +517,12 @@ def update_node(node, data):
     for name, input_plug in data['inputs'].items():
         node.inputs[name].value = input_plug['value']
         for sub_name, sub_plug in input_plug['sub_plugs'].items():
-            for sub_output in sub_plug['connections'].values():
-                node.inputs[name][sub_name].value = sub_plug['value']
-                node.inputs[name][sub_name].is_dirty = False
+            node.inputs[name][sub_name].value = sub_plug['value']
+            node.inputs[name][sub_name].is_dirty = False
         node.inputs[name].is_dirty = False
     for name, output_plug in data['outputs'].items():
         node.outputs[name].value = output_plug['value']
         for sub_name, sub_plug in output_plug['sub_plugs'].items():
-            for sub_output in sub_plug['connections'].values():
-                node.outputs[name][sub_name].value = sub_plug['value']
-                node.outputs[name][sub_name].is_dirty = False
+            node.outputs[name][sub_name].value = sub_plug['value']
+            node.outputs[name][sub_name].is_dirty = False
         node.outputs[name].is_dirty = False
diff --git a/requirements.txt b/requirements.txt
index 58c6567..ea4d927 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,3 @@
 ascii-canvas>=1.3.5
 ordereddict==1.1
 strip-hints>=0.1.7
-


Test patch:
diff --git a/tests/test_graph.py b/tests/test_graph.py
index 51a4909..6a0ad1a 100644
--- a/tests/test_graph.py
+++ b/tests/test_graph.py
@@ -174,22 +174,23 @@ def test_serialize_graph_to_pickle(clear_default_graph, branching_graph):
 def test_string_representations(clear_default_graph, branching_graph):
     """Print the Graph."""
 
-    assert str(branching_graph) == """+------------+          +------------+          +--------------------+
-|   Start    |          |   Node1    |          |        End         |
-|------------|          |------------|          |--------------------|
-o in1<>      |     +--->o in1<>      |          % in1                |
-o in2<>      |     |    o in2<>      |     +--->o  in1.1<>           |
-|        out o-----+    |        out o-----+--->o  in1.2<>           |
-|       out2 o     |    |       out2 o     |    o in2<>              |
-+------------+     |    +------------+     |    |                out o
-                   |    +------------+     |    |               out2 o
-                   |    |   Node2    |     |    +--------------------+
-                   |    |------------|     |                          
-                   +--->o in1<>      |     |                          
-                        o in2<>      |     |                          
-                        |        out o-----+                          
-                        |       out2 o                                
-                        +------------+                                """
+    assert str(branching_graph) == (
+"+------------+          +------------+          +--------------------+\n"
+"|   Start    |          |   Node1    |          |        End         |\n"
+"|------------|          |------------|          |--------------------|\n"
+"o in1<>      |     +--->o in1<>      |          % in1                |\n"
+"o in2<>      |     |    o in2<>      |     +--->o  in1.1<>           |\n"
+"|        out o-----+    |        out o-----+--->o  in1.2<>           |\n"
+"|       out2 o     |    |       out2 o     |    o in2<>              |\n"
+"+------------+     |    +------------+     |    |                out o\n"
+"                   |    +------------+     |    |               out2 o\n"
+"                   |    |   Node2    |     |    +--------------------+\n"
+"                   |    |------------|     |                          \n"
+"                   +--->o in1<>      |     |                          \n"
+"                        o in2<>      |     |                          \n"
+"                        |        out o-----+                          \n"
+"                        |       out2 o                                \n"
+"                        +------------+                                ")
 
     assert branching_graph.list_repr() == """TestGraph
  Start
@@ -260,6 +261,28 @@ def test_nodes_can_be_added_to_graph(clear_default_graph):
     assert 1 == len(graph.nodes)
 
 
+def test_nodes_can_be_deleted(clear_default_graph, branching_graph):
+    """All connections are cleared before the node object is deleted."""
+    branching_graph["Start"].outputs["out"]["0"].connect(
+        branching_graph["Node2"].inputs["in1"]["0"])
+    branching_graph["Start"].outputs["out"]["1"].connect(
+        branching_graph["Node2"].inputs["in1"])
+    branching_graph["Start"].outputs["out"].connect(
+        branching_graph["Node2"].inputs["in1"]["1"])
+
+    branching_graph.delete_node(branching_graph["Node2"])
+    assert 3 == len(branching_graph.nodes)
+
+    branching_graph.delete_node(branching_graph["Node1"])
+    assert 2 == len(branching_graph.nodes)
+
+    branching_graph.delete_node(branching_graph["Start"])
+    assert 1 == len(branching_graph.nodes)
+
+    branching_graph.delete_node(branching_graph["End"])
+    assert 0 == len(branching_graph.nodes)
+
+
 def test_nested_graphs_expand_sub_graphs(clear_default_graph):
     """Nested Graphs expand all nodes of their sub graphs on evaluation.