Repository: networkx/networkx

Issue:
Test warnings in networkx/drawing/tests/test_pylab.py
<!-- 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 -->
I met two warnings below when running tests:

```
PYTHONPATH=. pytest -v networkx/drawing/tests/test_pylab.py::test_house_with_colors
================================================== test session starts ===================================================
platform darwin -- Python 3.12.4, pytest-8.3.2, pluggy-1.5.0 -- /opt/homebrew/Caskroom/miniforge/base/envs/networkx-dev/bin/python3.12
cachedir: .pytest_cache
rootdir: /Users/isaiah/Documents/open_source/networkx
configfile: pyproject.toml
plugins: cov-5.0.0
collected 1 item                                                                                                         

networkx/drawing/tests/test_pylab.py::test_house_with_colors PASSED                                                [100%]

==================================================== warnings summary ====================================================
networkx/drawing/tests/test_pylab.py:424
  /Users/isaiah/Documents/open_source/networkx/networkx/drawing/tests/test_pylab.py:424: PytestUnknownMarkWarning: Unknown pytest.mark.mpl_image_compare - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    @pytest.mark.mpl_image_compare

networkx/drawing/tests/test_pylab.py::test_house_with_colors
  /opt/homebrew/Caskroom/miniforge/base/envs/networkx-dev/lib/python3.12/site-packages/_pytest/python.py:163: PytestReturnNotNoneWarning: Expected None, but networkx/drawing/tests/test_pylab.py::test_house_with_colors returned <Figure size 460.8x345.6 with 1 Axes>, which will be an error in a future version of pytest.  Did you mean to use `assert` instead of `return`?
    warnings.warn(

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
============================================= 1 passed, 2 warnings in 0.30s ==============================================
```
### Questions

<!--- Tell us what should happen -->

- First warning: it looks like registering marker in pyproject.toml could resolve it.
- Second warning: I don't understand why there is a return fig in test_house_with_colors function. 

```
@pytest.mark.mpl_image_compare
def test_house_with_colors():
    G = nx.house_graph()
    # explicitly set positions
    fig, ax = plt.subplots()
    pos = {0: (0, 0), 1: (1, 0), 2: (0, 1), 3: (1, 1), 4: (0.5, 2.0)}

    # Plot nodes with different properties for the "wall" and "roof" nodes
    nx.draw_networkx_nodes(
        G,
        pos,
        node_size=3000,
        nodelist=[0, 1, 2, 3],
        node_color="tab:blue",
    )
    nx.draw_networkx_nodes(
        G, pos, node_size=2000, nodelist=[4], node_color="tab:orange"
    )
    nx.draw_networkx_edges(G, pos, alpha=0.5, width=6)
    # Customize axes
    ax.margins(0.11)
    plt.tight_layout()
    plt.axis("off")
    return fig
```

### Steps to Reproduce

<!--- Provide a minimal example that reproduces the bug -->
`PYTHONPATH=. pytest -v networkx/drawing/tests/test_pylab.py::test_house_with_colors`

### Environment

<!--- Please provide details about your local environment -->

Python version: 3.12.4
NetworkX version: 3.4.2


Discussion:

Patch:
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index d78dbd170..98025e933 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -373,6 +373,15 @@ We will help you create the tests and sort out any kind of problem during code r
 Image comparison
 ~~~~~~~~~~~~~~~~
 
+.. note::
+   Image comparison tests require the ``pytest-mpl`` extension, which can be
+   installed with::
+
+      pip install pytest-mpl
+
+   If ``pytest-mpl`` is not installed, the test suite may emit warnings related
+   to ``pytest.mark.mpl_image_compare`` - these can be safely ignored.
+
 To run image comparisons::
 
     $ PYTHONPATH=. pytest --mpl --pyargs networkx.drawing
diff --git a/doc/developer/deprecations.rst b/doc/developer/deprecations.rst
index 46555e7b7..35fb95872 100644
--- a/doc/developer/deprecations.rst
+++ b/doc/developer/deprecations.rst
@@ -48,10 +48,6 @@ Version 3.5
 * Remove ``d_separated`` from ``algorithms/d_separation.py``.
 * Remove ``minimal_d_separator`` from ``algorithms/d_separation.py``.
 * Add `not_implemented_for("multigraph”)` decorator to ``k_core``, ``k_shell``, ``k_crust`` and ``k_corona`` functions.
-* Change ``single_target_shortest_path_length`` in ``algorithms/shortest_path/unweighted.py``
-  to return a dict. See #6527
-* Change ``shortest_path`` in ``algorithms/shortest_path/generic.py``
-  to return a iterator. See #6527
 * Remove ``total_spanning_tree_weight`` from ``linalg/laplacianmatrix.py``
 * Remove ``create`` keyword argument from ``nonisomorphic_trees`` in 
   ``generators/nonisomorphic_trees``.
diff --git a/examples/algorithms/plot_bipartite_motif_abcore.py b/examples/algorithms/plot_bipartite_motif_abcore.py
new file mode 100644
index 000000000..11b80d623
--- /dev/null
+++ b/examples/algorithms/plot_bipartite_motif_abcore.py
@@ -0,0 +1,36 @@
+"""
+--------------------------
+Bipartite Motifs: α/β-core
+--------------------------
+
+The alpha-beta core of a bipartite graph is a maximal subgraph where each node
+in the top set has at least ``alpha`` neighbors and each node in bottom set has
+at least ``beta`` neightbors.
+"""
+
+import networkx as nx
+import matplotlib.pyplot as plt
+
+# A connected bipartite graph
+G = nx.bipartite.havel_hakimi_graph(
+    [1, 2, 3, 2, 1, 2, 3, 2], [5, 7, 1, 1, 2], create_using=nx.Graph
+)
+U, V = nx.bipartite.sets(G)
+
+
+# Compute the alpha/beta-core of G
+alpha, beta = 2, 3
+G_core = G.copy()
+while remove_nodes := [
+    n for n, d in G_core.degree() if ((n in U and d < alpha) or (n in V and d < beta))
+]:
+    G_core.remove_nodes_from(remove_nodes)
+print(f"Nodes comprising the α({alpha})/β({beta})-core of G: {set(G_core.nodes)}")
+
+# Visualize the graph
+fig, ax = plt.subplots()
+pos = nx.bipartite_layout(G, nodes=U)
+nx.draw(G, pos=pos, ax=ax, with_labels=True)
+# Highlight the nodes of the a/b core in red
+nx.draw_networkx_nodes(G, pos=pos, nodelist=list(G_core), node_color="tab:red")
+plt.show()
diff --git a/networkx/algorithms/approximation/traveling_salesman.py b/networkx/algorithms/approximation/traveling_salesman.py
index f2c37d9cc..fd606700f 100644
--- a/networkx/algorithms/approximation/traveling_salesman.py
+++ b/networkx/algorithms/approximation/traveling_salesman.py
@@ -438,7 +438,7 @@ def asadpour_atsp(G, weight="weight", seed=None, source=None):
 
     # Check that G is a complete graph
     N = len(G) - 1
-    if N < 2:
+    if N < 1:
         raise nx.NetworkXError("G must have at least two nodes")
     # This check ignores selfloops which is what we want here.
     if any(len(nbrdict) - (n in nbrdict) != N for n, nbrdict in G.adj.items()):
@@ -446,6 +446,11 @@ def asadpour_atsp(G, weight="weight", seed=None, source=None):
     # Check that the source vertex, if given, is in the graph
     if source is not None and source not in G.nodes:
         raise nx.NetworkXError("Given source node not in G.")
+    # handle 2 node case
+    if N == 1:
+        if source is None:
+            return list(G)
+        return [source, next(n for n in G if n != source)]
 
     opt_hk, z_star = held_karp_ascent(G, weight)
 
diff --git a/networkx/algorithms/centrality/reaching.py b/networkx/algorithms/centrality/reaching.py
index 378e8a058..23018af0b 100644
--- a/networkx/algorithms/centrality/reaching.py
+++ b/networkx/algorithms/centrality/reaching.py
@@ -103,9 +103,9 @@ def global_reaching_centrality(G, weight=None, normalized=True):
         def as_distance(u, v, d):
             return total_weight / d.get(weight, 1)
 
-        shortest_paths = nx.shortest_path(G, weight=as_distance)
+        shortest_paths = dict(nx.shortest_path(G, weight=as_distance))
     else:
-        shortest_paths = nx.shortest_path(G)
+        shortest_paths = dict(nx.shortest_path(G))
 
     centrality = local_reaching_centrality
     # TODO This can be trivially parallelized.
diff --git a/networkx/drawing/nx_pylab.py b/networkx/drawing/nx_pylab.py
index c4d24cc07..f3cee9835 100644
--- a/networkx/drawing/nx_pylab.py
+++ b/networkx/drawing/nx_pylab.py
@@ -1385,47 +1385,64 @@ def draw_networkx_edge_labels(
                 has not been added yet, and doesn't have transform
             """
             dpi_cor = arrow._dpi_cor
-            # trans_data = arrow.get_transform()
             trans_data = self.ax.transData
-            if arrow._posA_posB is not None:
-                posA = arrow._convert_xy_units(arrow._posA_posB[0])
-                posB = arrow._convert_xy_units(arrow._posA_posB[1])
-                (posA, posB) = trans_data.transform((posA, posB))
-                _path = arrow.get_connectionstyle()(
-                    posA,
-                    posB,
-                    patchA=arrow.patchA,
-                    patchB=arrow.patchB,
-                    shrinkA=arrow.shrinkA * dpi_cor,
-                    shrinkB=arrow.shrinkB * dpi_cor,
+            if arrow._posA_posB is None:
+                raise ValueError(
+                    "Can only draw labels for fancy arrows with "
+                    "posA and posB inputs, not custom path"
                 )
-            else:
-                _path = trans_data.transform_path(arrow._path_original)
+            posA = arrow._convert_xy_units(arrow._posA_posB[0])
+            posB = arrow._convert_xy_units(arrow._posA_posB[1])
+            (posA, posB) = trans_data.transform((posA, posB))
+            _path = arrow.get_connectionstyle()(
+                posA,
+                posB,
+                patchA=arrow.patchA,
+                patchB=arrow.patchB,
+                shrinkA=arrow.shrinkA * dpi_cor,
+                shrinkB=arrow.shrinkB * dpi_cor,
+            )
             # Return is in display coordinates
             return _path
 
         def _update_text_pos_angle(self, arrow):
             # Fractional label position
-            path_disp = self._get_arrow_path_disp(arrow)
-            (x1, y1), (cx, cy), (x2, y2) = path_disp.vertices
             # Text position at a proportion t along the line in display coords
             # default is 0.5 so text appears at the halfway point
             t = self.label_pos
             tt = 1 - t
-            x = tt**2 * x1 + 2 * t * tt * cx + t**2 * x2
-            y = tt**2 * y1 + 2 * t * tt * cy + t**2 * y2
+            path_disp = self._get_arrow_path_disp(arrow)
+            is_bar_style = isinstance(
+                arrow.get_connectionstyle(), mpl.patches.ConnectionStyle.Bar
+            )
+            # 1. Calculate x and y
+            if is_bar_style:
+                # Bar Connection Style - straight line
+                _, (cx1, cy1), (cx2, cy2), _ = path_disp.vertices
+                x = cx1 * tt + cx2 * t
+                y = cy1 * tt + cy2 * t
+            else:
+                # Arc or Angle type Connection Styles - Bezier curve
+                (x1, y1), (cx, cy), (x2, y2) = path_disp.vertices
+                x = tt**2 * x1 + 2 * t * tt * cx + t**2 * x2
+                y = tt**2 * y1 + 2 * t * tt * cy + t**2 * y2
+            # 2. Calculate Angle
             if self.labels_horizontal:
                 # Horizontal text labels
                 angle = 0
             else:
                 # Labels parallel to curve
-                change_x = 2 * tt * (cx - x1) + 2 * t * (x2 - cx)
-                change_y = 2 * tt * (cy - y1) + 2 * t * (y2 - cy)
-                angle = (np.arctan2(change_y, change_x) / (2 * np.pi)) * 360
+                if is_bar_style:
+                    change_x = (cx2 - cx1) / 2
+                    change_y = (cy2 - cy1) / 2
+                else:
+                    change_x = 2 * tt * (cx - x1) + 2 * t * (x2 - cx)
+                    change_y = 2 * tt * (cy - y1) + 2 * t * (y2 - cy)
+                angle = np.arctan2(change_y, change_x) / (2 * np.pi) * 360
                 # Text is "right way up"
                 if angle > 90:
                     angle -= 180
-                if angle < -90:
+                elif angle < -90:
                     angle += 180
             (x, y) = self.ax.transData.inverted().transform((x, y))
             return x, y, angle
diff --git a/networkx/generators/geometric.py b/networkx/generators/geometric.py
index 29bd29376..fdd4f627b 100644
--- a/networkx/generators/geometric.py
+++ b/networkx/generators/geometric.py
@@ -246,10 +246,10 @@ def soft_random_geometric_graph(
         connecting two nodes that are of distance, dist, computed by the
         Minkowski distance metric. The probability density function, `p_dist`,
         must be any function that takes the metric value as input
-        and outputs a single probability value between 0-1. The scipy.stats
+        and outputs a single probability value between 0-1. The `scipy.stats`
         package has many probability distribution functions implemented and
         tools for custom probability distribution definitions [2], and passing
-        the .pdf method of scipy.stats distributions can be used here.  If the
+        the .pdf method of `scipy.stats` distributions can be used here.  If the
         probability function, `p_dist`, is not supplied, the default function
         is an exponential distribution with rate parameter :math:`\lambda=1`.
     seed : integer, random_state, or None (default)
@@ -268,6 +268,15 @@ def soft_random_geometric_graph(
         ``pos`` keyword argument or, if ``pos`` was not provided, as
         generated by this function.
 
+    Notes
+    -----
+    This uses a *k*-d tree to build the graph.
+
+    References
+    ----------
+    .. [1] Penrose, Mathew D. "Connectivity of soft random geometric graphs."
+           The Annals of Applied Probability 26.2 (2016): 986-1028.
+
     Examples
     --------
     Default Graph:
@@ -276,40 +285,25 @@ def soft_random_geometric_graph(
 
     Custom Graph:
 
-    Create a soft random geometric graph on 100 uniformly distributed nodes
-    where nodes are joined by an edge with probability computed from an
-    exponential distribution with rate parameter :math:`\lambda=1` if their
-    Euclidean distance is at most 0.2.
-
-    Notes
-    -----
-    This uses a *k*-d tree to build the graph.
-
     The `pos` keyword argument can be used to specify node positions so you
     can create an arbitrary distribution and domain for positions.
 
-    For example, to use a 2D Gaussian distribution of node positions with mean
-    (0, 0) and standard deviation 2
-
-    The scipy.stats package can be used to define the probability distribution
-    with the .pdf method used as `p_dist`.
+    The `scipy.stats` package can be used to define the probability distribution
+    with the ``.pdf`` method used as `p_dist`.
 
-    ::
+    For example, create a soft random geometric graph on 100 nodes using a 2D
+    Gaussian distribution of node positions with mean (0, 0) and standard deviation 2,
+    where nodes are joined by an edge with probability computed from an
+    exponential distribution with rate parameter :math:`\lambda=1` if their
+    Euclidean distance is at most 0.2.
 
     >>> import random
-    >>> import math
+    >>> from scipy.stats import expon
     >>> n = 100
     >>> pos = {i: (random.gauss(0, 2), random.gauss(0, 2)) for i in range(n)}
-    >>> p_dist = lambda dist: math.exp(-dist)
+    >>> p_dist = lambda x: expon.pdf(x, scale=1)
     >>> G = nx.soft_random_geometric_graph(n, 0.2, pos=pos, p_dist=p_dist)
 
-    References
-    ----------
-    .. [1] Penrose, Mathew D. "Connectivity of soft random geometric graphs."
-           The Annals of Applied Probability 26.2 (2016): 986-1028.
-    .. [2] scipy.stats -
-           https://docs.scipy.org/doc/scipy/reference/tutorial/stats.html
-
     """
     G = nx.empty_graph(n)
     G.name = f"soft_random_geometric_graph({n}, {radius}, {dim})"
@@ -405,7 +399,7 @@ def geographical_threshold_graph(
         density functions. The :mod:`scipy.stats` package has many
         probability density functions implemented and tools for custom
         probability density definitions, and passing the ``.pdf`` method of
-        scipy.stats distributions can be used here. If ``p_dist=None``
+        `scipy.stats` distributions can be used here. If ``p_dist=None``
         (the default), the exponential function :math:`r^{-2}` is used.
     seed : integer, random_state, or None (default)
         Indicator of random number generation state.
@@ -783,6 +777,14 @@ def thresholded_random_geometric_graph(
         attribute ``'weight'`` that stores the weight of that node as
         provided or as generated.
 
+    Notes
+    -----
+    This uses a *k*-d tree to build the graph.
+
+    References
+    ----------
+    .. [1] http://cole-maclean.github.io/blog/files/thesis.pdf
+
     Examples
     --------
     Default Graph:
@@ -791,39 +793,26 @@ def thresholded_random_geometric_graph(
 
     Custom Graph:
 
-    Create a thresholded random geometric graph on 50 uniformly distributed
-    nodes where nodes are joined by an edge if their sum weights drawn from
-    a exponential distribution with rate = 5 are >= theta = 0.1 and their
-    Euclidean distance is at most 0.2.
-
-    Notes
-    -----
-    This uses a *k*-d tree to build the graph.
-
     The `pos` keyword argument can be used to specify node positions so you
     can create an arbitrary distribution and domain for positions.
 
-    For example, to use a 2D Gaussian distribution of node positions with mean
-    (0, 0) and standard deviation 2
-
     If weights are not specified they are assigned to nodes by drawing randomly
     from the exponential distribution with rate parameter :math:`\lambda=1`.
     To specify weights from a different distribution, use the `weight` keyword
-    argument::
+    argument.
 
-    ::
+    For example, create a thresholded random geometric graph on 50 nodes using a 2D
+    Gaussian distribution of node positions with mean (0, 0) and standard deviation 2,
+    where nodes are joined by an edge if their sum weights drawn from
+    a exponential distribution with rate = 5 are >= theta = 0.1 and their
+    Euclidean distance is at most 0.2.
 
     >>> import random
-    >>> import math
     >>> n = 50
     >>> pos = {i: (random.gauss(0, 2), random.gauss(0, 2)) for i in range(n)}
     >>> w = {i: random.expovariate(5.0) for i in range(n)}
     >>> G = nx.thresholded_random_geometric_graph(n, 0.2, 0.1, 2, pos, w)
 
-    References
-    ----------
-    .. [1] http://cole-maclean.github.io/blog/files/thesis.pdf
-
     """
     G = nx.empty_graph(n)
     G.name = f"thresholded_random_geometric_graph({n}, {radius}, {theta}, {dim})"


Test patch:
diff --git a/networkx/algorithms/approximation/tests/test_traveling_salesman.py b/networkx/algorithms/approximation/tests/test_traveling_salesman.py
index bb309fc70..7d07ead7f 100644
--- a/networkx/algorithms/approximation/tests/test_traveling_salesman.py
+++ b/networkx/algorithms/approximation/tests/test_traveling_salesman.py
@@ -939,6 +939,20 @@ def test_asadpour_empty_graph():
     pytest.raises(nx.NetworkXError, nx_app.asadpour_atsp, G)
 
 
+def test_asadpour_small_graphs():
+    # 1 node
+    G = nx.path_graph(1, create_using=nx.DiGraph)
+    with pytest.raises(nx.NetworkXError, match="at least two nodes"):
+        nx_app.asadpour_atsp(G)
+
+    # 2 nodes
+    G = nx.DiGraph()
+    G.add_weighted_edges_from([(0, 1, 7), (1, 0, 8)])
+    assert nx_app.asadpour_atsp(G) in [[0, 1], [1, 0]]
+    assert nx_app.asadpour_atsp(G, source=1) == [1, 0]
+    assert nx_app.asadpour_atsp(G, source=0) == [0, 1]
+
+
 @pytest.mark.slow
 def test_asadpour_integral_held_karp():
     """
diff --git a/networkx/algorithms/shortest_paths/generic.py b/networkx/algorithms/shortest_paths/generic.py
index 9ac48c90f..d85f46e52 100644
--- a/networkx/algorithms/shortest_paths/generic.py
+++ b/networkx/algorithms/shortest_paths/generic.py
@@ -76,7 +76,7 @@ def shortest_path(G, source=None, target=None, weight=None, method="dijkstra"):
 
     Returns
     -------
-    path: list or dictionary
+    path: list or dictionary or iterator
         All returned paths include both the source and target in the path.
 
         If the source and target are both specified, return a single list
@@ -90,8 +90,9 @@ def shortest_path(G, source=None, target=None, weight=None, method="dijkstra"):
         sources with a list of nodes in a shortest path from one of the
         sources to the target.
 
-        If neither the source nor target are specified return a dictionary
-        of dictionaries with path[source][target]=[list of nodes in path].
+        If neither the source nor target are specified, return an iterator
+        over (source, dictionary) where dictionary is keyed by target to
+        list of nodes in a shortest path from the source to the target.
 
     Raises
     ------
@@ -136,25 +137,13 @@ def shortest_path(G, source=None, target=None, weight=None, method="dijkstra"):
     method = "unweighted" if weight is None else method
     if source is None:
         if target is None:
-            warnings.warn(
-                (
-                    "\n\nshortest_path will return an iterator that yields\n"
-                    "(node, path) pairs instead of a dictionary when source\n"
-                    "and target are unspecified beginning in version 3.5\n\n"
-                    "To keep the current behavior, use:\n\n"
-                    "\tdict(nx.shortest_path(G))"
-                ),
-                FutureWarning,
-                stacklevel=3,
-            )
-
-            # Find paths between all pairs.
+            # Find paths between all pairs. Iterator of dicts.
             if method == "unweighted":
-                paths = dict(nx.all_pairs_shortest_path(G))
+                paths = nx.all_pairs_shortest_path(G)
             elif method == "dijkstra":
-                paths = dict(nx.all_pairs_dijkstra_path(G, weight=weight))
+                paths = nx.all_pairs_dijkstra_path(G, weight=weight)
             else:  # method == 'bellman-ford':
-                paths = dict(nx.all_pairs_bellman_ford_path(G, weight=weight))
+                paths = nx.all_pairs_bellman_ford_path(G, weight=weight)
         else:
             # Find paths from all nodes co-accessible to the target.
             if G.is_directed():
diff --git a/networkx/algorithms/shortest_paths/tests/test_generic.py b/networkx/algorithms/shortest_paths/tests/test_generic.py
index e30de5177..25e933baa 100644
--- a/networkx/algorithms/shortest_paths/tests/test_generic.py
+++ b/networkx/algorithms/shortest_paths/tests/test_generic.py
@@ -212,9 +212,9 @@ class TestGenericPath:
         assert sorted(ans[4]) == [[4]]
 
     def test_all_pairs_shortest_path(self):
-        # shortest_path w/o source and target will return a generator instead of
-        # a dict beginning in version 3.5. Only the first call needs changed here.
-        p = nx.shortest_path(self.cycle)
+        # shortest_path w/o source and target returns a generator instead of
+        # a dict beginning in version 3.5. Only the first call needed changed here.
+        p = dict(nx.shortest_path(self.cycle))
         assert p[0][3] == [0, 1, 2, 3]
         assert p == dict(nx.all_pairs_shortest_path(self.cycle))
         p = dict(nx.shortest_path(self.grid))
diff --git a/networkx/algorithms/shortest_paths/tests/test_unweighted.py b/networkx/algorithms/shortest_paths/tests/test_unweighted.py
index f09c8b104..4adbd84de 100644
--- a/networkx/algorithms/shortest_paths/tests/test_unweighted.py
+++ b/networkx/algorithms/shortest_paths/tests/test_unweighted.py
@@ -92,9 +92,9 @@ class TestUnweightedPath:
     def test_single_target_shortest_path_length(self):
         pl = nx.single_target_shortest_path_length
         lengths = {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1}
-        assert dict(pl(self.cycle, 0)) == lengths
+        assert pl(self.cycle, 0) == lengths
         lengths = {0: 0, 1: 6, 2: 5, 3: 4, 4: 3, 5: 2, 6: 1}
-        assert dict(pl(self.directed_cycle, 0)) == lengths
+        assert pl(self.directed_cycle, 0) == lengths
         # test missing targets
         target = 8
         with pytest.raises(nx.NodeNotFound, match=f"Target {target} is not in G"):
diff --git a/networkx/algorithms/shortest_paths/unweighted.py b/networkx/algorithms/shortest_paths/unweighted.py
index 3aeef8547..fed6dece8 100644
--- a/networkx/algorithms/shortest_paths/unweighted.py
+++ b/networkx/algorithms/shortest_paths/unweighted.py
@@ -112,13 +112,13 @@ def single_target_shortest_path_length(G, target, cutoff=None):
 
     Returns
     -------
-    lengths : iterator
-        (source, shortest path length) iterator
+    lengths : dictionary
+        Dictionary, keyed by source, of shortest path lengths.
 
     Examples
     --------
     >>> G = nx.path_graph(5, create_using=nx.DiGraph())
-    >>> length = dict(nx.single_target_shortest_path_length(G, 4))
+    >>> length = nx.single_target_shortest_path_length(G, 4)
     >>> length[0]
     4
     >>> for node in range(5):
@@ -135,24 +135,12 @@ def single_target_shortest_path_length(G, target, cutoff=None):
     """
     if target not in G:
         raise nx.NodeNotFound(f"Target {target} is not in G")
-
-    warnings.warn(
-        (
-            "\n\nsingle_target_shortest_path_length will return a dict instead of"
-            "\nan iterator in version 3.5"
-        ),
-        FutureWarning,
-        stacklevel=3,
-    )
-
     if cutoff is None:
         cutoff = float("inf")
     # handle either directed or undirected
     adj = G._pred if G.is_directed() else G._adj
     nextlevel = [target]
-    # for version 3.3 we will return a dict like this:
-    # return dict(_single_shortest_path_length(adj, nextlevel, cutoff))
-    return _single_shortest_path_length(adj, nextlevel, cutoff)
+    return dict(_single_shortest_path_length(adj, nextlevel, cutoff))
 
 
 @nx._dispatchable
diff --git a/networkx/classes/tests/test_subgraphviews.py b/networkx/classes/tests/test_subgraphviews.py
index 7f70b29ce..66d570ced 100644
--- a/networkx/classes/tests/test_subgraphviews.py
+++ b/networkx/classes/tests/test_subgraphviews.py
@@ -361,11 +361,11 @@ class TestEdgeSubGraph:
         pytest.raises(nx.NetworkXError, self.H.add_edge, 5, 6)
         pytest.raises(nx.NetworkXError, self.H.remove_edge, 0, 1)
 
-    def test_consistent_edges(self):
-        # See gh-7724.
-        """Tests that the subgraph returns consistent filtered edges."""
-        G = nx.MultiDiGraph()
-        G.add_edges_from([("a", "b"), ("a", "c"), ("c", "b")])
+    @pytest.mark.parametrize("multigraph", (nx.MultiGraph, nx.MultiDiGraph))
+    def test_multigraph_filtered_edges(self, multigraph):
+        """Check edge visibility in FilterMultiInner on edge_subgraph's of
+        multigraphs. See gh-7724."""
+        G = multigraph([("a", "b"), ("a", "c"), ("c", "b")])
         H = nx.edge_subgraph(G, [("a", "b", 0), ("c", "b", 0)])
         assert "c" not in H["a"]
         assert not H.has_edge("a", "c")
diff --git a/networkx/conftest.py b/networkx/conftest.py
index 4a261c6d0..5b591463f 100644
--- a/networkx/conftest.py
+++ b/networkx/conftest.py
@@ -100,16 +100,6 @@ def pytest_collection_modifyitems(config, items):
 # TODO: The warnings below need to be dealt with, but for now we silence them.
 @pytest.fixture(autouse=True)
 def set_warnings():
-    warnings.filterwarnings(
-        "ignore",
-        category=FutureWarning,
-        message="\n\nsingle_target_shortest_path_length",
-    )
-    warnings.filterwarnings(
-        "ignore",
-        category=FutureWarning,
-        message="\n\nshortest_path",
-    )
     warnings.filterwarnings(
         "ignore", category=DeprecationWarning, message="\n\nThe `normalized`"
     )
@@ -252,6 +242,7 @@ needs_scipy = [
     "drawing/layout.py",
     "drawing/nx_pylab.py",
     "generators/spectral_graph_forge.py",
+    "generators/geometric.py",
     "generators/expanders.py",
     "linalg/algebraicconnectivity.py",
     "linalg/attrmatrix.py",
diff --git a/networkx/drawing/tests/test_pylab.py b/networkx/drawing/tests/test_pylab.py
index 4fe3b7468..355ab5abf 100644
--- a/networkx/drawing/tests/test_pylab.py
+++ b/networkx/drawing/tests/test_pylab.py
@@ -1026,3 +1026,27 @@ def test_hide_ticks(method, hide_ticks):
 
     plt.delaxes(ax)
     plt.close()
+
+
+def test_edge_label_bar_connectionstyle():
+    """Check that FancyArrowPatches with `bar` connectionstyle are also supported
+    in edge label rendering. See gh-7735."""
+    edge = (0, 1)
+    G = nx.DiGraph([edge])
+    pos = {n: (n, 0) for n in G}  # Edge is horizontal line between (0, 0) and (1, 0)
+
+    style_arc = "arc3,rad=0.0"
+    style_bar = "bar,fraction=0.1"
+
+    arc_lbl = nx.draw_networkx_edge_labels(
+        G, pos, edge_labels={edge: "edge"}, connectionstyle=style_arc
+    )
+    # This would fail prior to gh-7739
+    bar_lbl = nx.draw_networkx_edge_labels(
+        G, pos, edge_labels={edge: "edge"}, connectionstyle=style_bar
+    )
+
+    # For the "arc" style, the label should be at roughly the midpoint
+    assert arc_lbl[edge].x, arc_lbl[edge].y == pytest.approx((0.5, 0))
+    # The label should be below the x-axis for the "bar" style
+    assert bar_lbl[edge].y < arc_lbl[edge].y