Repository: networkx/networkx

Issue:
`json_graph.tree_data` can cause maximum recursion depth error.
<!-- If you have a general question about NetworkX, please use the discussions tab to create a new discussion -->

<!--- Provide a general summary of the issue in the Title above -->

### Current Behavior
<!--- Tell us what happens instead of the expected behavior -->
Currently the algorithm compares the `n_nodes` with `n_edges` to check if `G` is a tree. https://github.com/networkx/networkx/blob/0cc70051fa0a979b1f1eab4af5b6587a6ebf8334/networkx/readwrite/json_graph/tree.py#L74-L75 
This check can be bypassed with specific inputs and cause a recursion error.

### Expected Behavior
<!--- Tell us what should happen -->
The code should check whether there are cycles with `root` as the source and raise an exception.
Another possible fix would be to check if the graph is not weakly connected.

### Steps to Reproduce
<!--- Provide a minimal example that reproduces the bug -->
```Python3
>>> import networkx as nx
>>> G = nx.DiGraph([(1, 2), (2, 3), (3, 1)])
>>> G.add_node(4)
>>> data = nx.json_graph.tree_data(G, 1)
RecursionError: maximum recursion depth exceeded
```

### Environment
<!--- Please provide details about your local environment -->
Python version: 3.8.10
NetworkX version: 2.7rc1.dev0


Discussion:

Patch:
diff --git a/networkx/algorithms/community/louvain.py b/networkx/algorithms/community/louvain.py
index ba7153521..9ee9f51c4 100644
--- a/networkx/algorithms/community/louvain.py
+++ b/networkx/algorithms/community/louvain.py
@@ -185,6 +185,7 @@ def louvain_partitions(
         )
         if new_mod - mod <= threshold:
             return
+        mod = new_mod
         graph = _gen_graph(graph, inner_partition)
         partition, inner_partition, improvement = _one_level(
             graph, m, partition, resolution, is_directed, seed
diff --git a/networkx/readwrite/json_graph/tree.py b/networkx/readwrite/json_graph/tree.py
index 2de2ca9b6..615907eeb 100644
--- a/networkx/readwrite/json_graph/tree.py
+++ b/networkx/readwrite/json_graph/tree.py
@@ -75,6 +75,8 @@ def tree_data(G, root, attrs=None, ident="id", children="children"):
         raise TypeError("G is not a tree.")
     if not G.is_directed():
         raise TypeError("G is not directed.")
+    if not nx.is_weakly_connected(G):
+        raise TypeError("G is not weakly connected.")
 
     # NOTE: to be removed in 3.0
     if attrs is not None:


Test patch:
diff --git a/networkx/algorithms/community/tests/test_louvain.py b/networkx/algorithms/community/tests/test_louvain.py
index 81bde05b6..8f623fab1 100644
--- a/networkx/algorithms/community/tests/test_louvain.py
+++ b/networkx/algorithms/community/tests/test_louvain.py
@@ -110,3 +110,15 @@ def test_resolution():
     partition3 = louvain_communities(G, resolution=2, seed=12)
 
     assert len(partition1) <= len(partition2) <= len(partition3)
+
+
+def test_threshold():
+    G = nx.LFR_benchmark_graph(
+        250, 3, 1.5, 0.009, average_degree=5, min_community=20, seed=10
+    )
+    partition1 = louvain_communities(G, threshold=0.2, seed=2)
+    partition2 = louvain_communities(G, seed=2)
+    mod1 = modularity(G, partition1)
+    mod2 = modularity(G, partition2)
+
+    assert mod1 < mod2
diff --git a/networkx/readwrite/json_graph/tests/test_tree.py b/networkx/readwrite/json_graph/tests/test_tree.py
index bfbf18163..848edd0b1 100644
--- a/networkx/readwrite/json_graph/tests/test_tree.py
+++ b/networkx/readwrite/json_graph/tests/test_tree.py
@@ -35,6 +35,11 @@ def test_exceptions():
     with pytest.raises(TypeError, match="is not directed."):
         G = nx.path_graph(3)
         tree_data(G, 0)
+    with pytest.raises(TypeError, match="is not weakly connected."):
+        G = nx.path_graph(3, create_using=nx.DiGraph)
+        G.add_edge(2, 0)
+        G.add_node(3)
+        tree_data(G, 0)
     with pytest.raises(nx.NetworkXError, match="must be different."):
         G = nx.MultiDiGraph()
         G.add_node(0)