PaulSchweizer: Resolves #116 
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
-

Delete nodes from graph
`Graph.delete_node(node)` will break all connections of the node and delete the node object
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.
 

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest numpy>=1.16.0 pandas>=1.0.0
apt-get update apt-get install -y gcc
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
ascii-canvas==2.0.1
exceptiongroup==1.2.2
-e git+https://github.com/PaulSchweizer/flowpipe.git@2923e9789612b30ca96f9d261cddf4d9bc0b8f67#egg=flowpipe
iniconfig==2.1.0
numpy==2.0.2
ordereddict==1.1
packaging==24.2
pandas==2.2.3
pluggy==1.5.0
pytest==8.3.5
python-dateutil==2.9.0.post0
pytz==2025.2
six==1.17.0
strip-hints==0.1.13
tomli==2.2.1
tzdata==2025.2

name: flowpipe
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - ascii-canvas==2.0.1
      - exceptiongroup==1.2.2
      - iniconfig==2.1.0
      - numpy==2.0.2
      - ordereddict==1.1
      - packaging==24.2
      - pandas==2.2.3
      - pluggy==1.5.0
      - pytest==8.3.5
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - six==1.17.0
      - strip-hints==0.1.13
      - tomli==2.2.1
      - tzdata==2025.2
prefix: /opt/conda/envs/flowpipe

tests/test_graph.py::test_nodes_can_be_deleted
tests/test_graph.py::test_serialize_graph_to_pickle
tests/test_graph.py::test_evaluation_matrix tests/test_graph.py::test_linar_evaluation_sequence tests/test_graph.py::test_branching_evaluation_sequence tests/test_graph.py::test_complex_branching_evaluation_sequence tests/test_graph.py::test_serialize_graph_to_json tests/test_graph.py::test_string_representations tests/test_graph.py::test_string_representations_with_subgraphs tests/test_graph.py::test_nodes_can_be_added_to_graph tests/test_graph.py::test_nested_graphs_expand_sub_graphs tests/test_graph.py::test_nodes_can_be_accessed_via_name_through_indexing tests/test_graph.py::test_node_names_on_graph_have_to_be_unique tests/test_graph.py::test_nodes_are_only_added_once tests/test_graph.py::test_nodes_can_add_to_graph_on_init tests/test_graph.py::test_get_default_graph tests/test_graph.py::test_set_default_graph tests/test_graph.py::test_reset_default_graph tests/test_graph.py::test_threaded_evaluation tests/test_graph.py::test_valid_evaluation_mode tests/test_graph.py::test_invalid_evaluation_mode tests/test_graph.py::test_cycle_error_when_node_connects_to_itself tests/test_graph.py::test_cycle_error_when_node_connects_out_to_own_upstream tests/test_graph.py::test_cycle_error_when_node_connects_out_to_own_upstream_across_subgraphs
.github/ISSUE_TEMPLATE/feature_request.md .github/ISSUE_TEMPLATE/bug_report.md .gitignore flowpipe/graph.py requirements.txt
.github/ISSUE_TEMPLATE/feature_request.md .github/ISSUE_TEMPLATE/bug_report.md .gitignore flowpipe/graph.py requirements.txt