Repository: networkx/networkx

Issue:
Incorrectly returning [] when a generator is expected
This return value (`[]`) is not consistent with the intention of the `all_simple_paths` function:

```py
if source in targets:
    return []
```

From: https://github.com/networkx/networkx/blob/b0ca6ce081cc6e66d509c5f7fed60728da821c25/networkx/algorithms/simple_paths.py#L230

Context:

```py
def all_simple_paths(G, source, target, cutoff=None):
    """Generate all simple paths in the graph G from source to target.
    A simple path is a path with no repeated nodes.

    [...]

    Returns
    -------
    path_generator: generator
       A generator that produces lists of simple paths.  If there are no paths
       between the source and target within the given cutoff the generator
       produces no output.
```

I recommend, instead, that NetworkX provide a reusable empty generator function, such as:

```py
def empty_generator():
    yield from ()
```

Then, in `all_simple_paths` (and almost certainly, other places in the library), call `return empty_generator()`


Discussion:

Resolving patch:
diff --git a/networkx/algorithms/simple_paths.py b/networkx/algorithms/simple_paths.py
--- a/networkx/algorithms/simple_paths.py
+++ b/networkx/algorithms/simple_paths.py
@@ -5,6 +5,7 @@
 import networkx as nx
 from networkx.utils import not_implemented_for
 from networkx.utils import pairwise
+from networkx.utils import empty_generator
 from networkx.algorithms.shortest_paths.weighted import _weight_function
 
 __all__ = [
@@ -228,11 +229,11 @@ def all_simple_paths(G, source, target, cutoff=None):
         except TypeError:
             raise nx.NodeNotFound(f"target node {target} not in graph")
     if source in targets:
-        return []
+        return empty_generator()
     if cutoff is None:
         cutoff = len(G) - 1
     if cutoff < 1:
-        return []
+        return empty_generator()
     if G.is_multigraph():
         return _all_simple_paths_multigraph(G, source, targets, cutoff)
     else:
diff --git a/networkx/utils/misc.py b/networkx/utils/misc.py
--- a/networkx/utils/misc.py
+++ b/networkx/utils/misc.py
@@ -44,6 +44,11 @@ def iterable(obj):
     return True
 
 
+def empty_generator():
+    """ Return a generator with no members """
+    yield from ()
+
+
 def flatten(obj, result=None):
     """ Return flattened version of (possibly nested) iterable object. """
     if not iterable(obj) or is_string_like(obj):


Test patch:
diff --git a/networkx/algorithms/tests/test_simple_paths.py b/networkx/algorithms/tests/test_simple_paths.py
--- a/networkx/algorithms/tests/test_simple_paths.py
+++ b/networkx/algorithms/tests/test_simple_paths.py
@@ -135,7 +135,7 @@ def test_all_simple_paths_with_two_targets_inside_cycle_emits_two_paths():
 def test_all_simple_paths_source_target():
     G = nx.path_graph(4)
     paths = nx.all_simple_paths(G, 1, 1)
-    assert paths == []
+    assert list(paths) == []
 
 
 def test_all_simple_paths_cutoff():
@@ -164,7 +164,7 @@ def test_all_simple_paths_on_non_trivial_graph():
 def test_all_simple_paths_multigraph():
     G = nx.MultiGraph([(1, 2), (1, 2)])
     paths = nx.all_simple_paths(G, 1, 1)
-    assert paths == []
+    assert list(paths) == []
     nx.add_path(G, [3, 1, 10, 2])
     paths = list(nx.all_simple_paths(G, 1, 2))
     assert len(paths) == 3