Repository: networkx/networkx

Issue:
weakly_connected_components: Editing yielded sets during iteration has buggy side effects
When modifying the yielded component sets during iteration from `weakly_connected_components`, strange things happen:

```python
import networkx as nx
g = nx.MultiDiGraph()

g.add_edge(0, 1)                                                                      
g.add_edge(1, 0)                                                                      
g.add_edge(0, 3)                                                                      
g.add_edge(0, 3)                                                                      

print('Okay:')
print(list(nx.weakly_connected_components(g)))
# Everything alright, gives: [{0, 1, 3}]

print('Still okay:')
for n in nx.weakly_connected_components(g):
    print(n)
    n.remove(0)
# Will print once: {0, 1, 3}

print('NOT okay:')
# Deleting the wrong node during the iteration:
for n in nx.weakly_connected_components(g):
    print(n)
    n.remove(1)
# Will print the set twice:
# {0, 1, 3}
# {0, 1, 3}
```

In case this is actually desired (which I doubt), that should be at least documented that the connected component set is not to be edited.


Discussion:
As to date using the latest release v2.5.
```python
In [2]: nx.__version__                                                                        
Out[2]: '2.5'
```
This looks like a bug I believe we ran into elsewhere in the code before. The set that is yielded is added to the `seen` dictionary AFTER yielding. Therefore any changes to it affect whether the algorithm thinks it saw this set previously.   This is definitely a bug.  And should be easily fixed by updating the "seen" dictionary before yielding the set `c`.

While we do this, we need to check the other `weakly_connected` code and I see it in one place in the `strongly_connected` code as well... so we better look through that as well. 

Resolving patch:
diff --git a/networkx/algorithms/components/strongly_connected.py b/networkx/algorithms/components/strongly_connected.py
--- a/networkx/algorithms/components/strongly_connected.py
+++ b/networkx/algorithms/components/strongly_connected.py
@@ -166,8 +166,8 @@ def kosaraju_strongly_connected_components(G, source=None):
             continue
         c = nx.dfs_preorder_nodes(G, r)
         new = {v for v in c if v not in seen}
-        yield new
         seen.update(new)
+        yield new
 
 
 @not_implemented_for("undirected")
diff --git a/networkx/algorithms/components/weakly_connected.py b/networkx/algorithms/components/weakly_connected.py
--- a/networkx/algorithms/components/weakly_connected.py
+++ b/networkx/algorithms/components/weakly_connected.py
@@ -60,8 +60,8 @@ def weakly_connected_components(G):
     for v in G:
         if v not in seen:
             c = set(_plain_bfs(G, v))
-            yield c
             seen.update(c)
+            yield c
 
 
 @not_implemented_for("undirected")
@@ -162,7 +162,7 @@ def _plain_bfs(G, source):
         nextlevel = set()
         for v in thislevel:
             if v not in seen:
-                yield v
                 seen.add(v)
                 nextlevel.update(Gsucc[v])
                 nextlevel.update(Gpred[v])
+                yield v


Test patch:
diff --git a/networkx/algorithms/components/tests/test_strongly_connected.py b/networkx/algorithms/components/tests/test_strongly_connected.py
--- a/networkx/algorithms/components/tests/test_strongly_connected.py
+++ b/networkx/algorithms/components/tests/test_strongly_connected.py
@@ -188,6 +188,22 @@ def test_connected_raise(self):
         )
         pytest.raises(NetworkXNotImplemented, nx.condensation, G)
 
+    strong_cc_methods = (
+        nx.strongly_connected_components,
+        nx.kosaraju_strongly_connected_components,
+        nx.strongly_connected_components_recursive,
+    )
+
+    @pytest.mark.parametrize("get_components", strong_cc_methods)
+    def test_connected_mutability(self, get_components):
+        DG = nx.path_graph(5, create_using=nx.DiGraph)
+        G = nx.disjoint_union(DG, DG)
+        seen = set()
+        for component in get_components(G):
+            assert len(seen & component) == 0
+            seen.update(component)
+            component.clear()
+
 
 #    Commented out due to variability on Travis-CI hardware/operating systems
 #    def test_linear_time(self):
diff --git a/networkx/algorithms/components/tests/test_weakly_connected.py b/networkx/algorithms/components/tests/test_weakly_connected.py
--- a/networkx/algorithms/components/tests/test_weakly_connected.py
+++ b/networkx/algorithms/components/tests/test_weakly_connected.py
@@ -76,3 +76,12 @@ def test_connected_raise(self):
         pytest.raises(NetworkXNotImplemented, nx.weakly_connected_components, G)
         pytest.raises(NetworkXNotImplemented, nx.number_weakly_connected_components, G)
         pytest.raises(NetworkXNotImplemented, nx.is_weakly_connected, G)
+
+    def test_connected_mutability(self):
+        DG = nx.path_graph(5, create_using=nx.DiGraph)
+        G = nx.disjoint_union(DG, DG)
+        seen = set()
+        for component in nx.weakly_connected_components(G):
+            assert len(seen & component) == 0
+            seen.update(component)
+            component.clear()