Repository: networkx/networkx

Issue:
Refactor components API
Following from the discussion on #1404, it would be good to remove the `[bi]connected_component_subgraphs` functions and make `[bi]connected_components` yield subgraphs (now they yield sets of nodes).

We decided to not make this change right now, on the one hand, in order to not overwhelm users with API changes (2.0 release will come with many changes), and on the other hand, because right now generating subgraphs (with `copy=True` which is the default) is much slower than generating sets of nodes.

We expect that the speed of generating subgraphs will improve in the short term if we extend #1164 approach to subgraph generation. Once we do that we can revisit this to see if the speed penalty for subgraph generation is a showstoper for this API change.


Discussion:

Patch:
diff --git a/networkx/algorithms/components/attracting.py b/networkx/algorithms/components/attracting.py
index c1abc4822..e0861f63c 100644
--- a/networkx/algorithms/components/attracting.py
+++ b/networkx/algorithms/components/attracting.py
@@ -8,6 +8,7 @@
 #
 # Authors: Christopher Ellison
 """Attracting components."""
+import warnings as _warnings
 import networkx as nx
 from networkx.utils.decorators import not_implemented_for
 
@@ -20,7 +21,7 @@ __all__ = ['number_attracting_components',
 
 @not_implemented_for('undirected')
 def attracting_components(G):
-    """Generates a list of attracting components in `G`.
+    """Generates the attracting components in `G`.
 
     An attracting component in a directed graph `G` is a strongly connected
     component with the property that a random walker on the graph will never
@@ -49,7 +50,6 @@ def attracting_components(G):
     --------
     number_attracting_components
     is_attracting_component
-    attracting_component_subgraphs
 
     """
     scc = list(nx.strongly_connected_components(G))
@@ -82,11 +82,9 @@ def number_attracting_components(G):
     --------
     attracting_components
     is_attracting_component
-    attracting_component_subgraphs
 
     """
-    n = len(list(attracting_components(G)))
-    return n
+    return sum(1 for ac in attracting_components(G))
 
 
 @not_implemented_for('undirected')
@@ -112,49 +110,25 @@ def is_attracting_component(G):
     --------
     attracting_components
     number_attracting_components
-    attracting_component_subgraphs
 
     """
     ac = list(attracting_components(G))
-    if len(ac[0]) == len(G):
-        attracting = True
-    else:
-        attracting = False
-    return attracting
+    if len(ac) == 1:
+        return len(ac[0]) == len(G)
+    return False
 
 
 @not_implemented_for('undirected')
 def attracting_component_subgraphs(G, copy=True):
-    """Generates a list of attracting component subgraphs from `G`.
-
-    Parameters
-    ----------
-    G : DiGraph, MultiDiGraph
-        The graph to be analyzed.
-
-    Returns
-    -------
-    subgraphs : list
-        A list of node-induced subgraphs of the attracting components of `G`.
-
-    copy : bool
-        If copy is True, graph, node, and edge attributes are copied to the
-        subgraphs.
-
-    Raises
-    ------
-    NetworkXNotImplemented :
-        If the input graph is undirected.
-
-    See Also
-    --------
-    attracting_components
-    number_attracting_components
-    is_attracting_component
+    """DEPRECATED: Use ``(G.subgraph(c) for c in attracting_components(G))``
 
+           Or ``(G.subgraph(c).copy() for c in attracting_components(G))``
     """
-    for ac in attracting_components(G):
+    msg = "attracting_component_subgraphs is deprecated and will be removed" \
+        "in 2.2. Use (G.subgraph(c).copy() for c in attracting_components(G))"
+    _warnings.warn(msg, DeprecationWarning)
+    for c in attracting_components(G):
         if copy:
-            yield G.subgraph(ac).copy()
+            yield G.subgraph(c).copy()
         else:
-            yield G.subgraph(ac)
+            yield G.subgraph(c)
diff --git a/networkx/algorithms/components/biconnected.py b/networkx/algorithms/components/biconnected.py
index 255cd25e5..587249145 100644
--- a/networkx/algorithms/components/biconnected.py
+++ b/networkx/algorithms/components/biconnected.py
@@ -10,6 +10,7 @@
 #          Dan Schult (dschult@colgate.edu)
 #          Aric Hagberg (aric.hagberg@gmail.com)
 """Biconnected components and articulation points."""
+import warnings as _warnings
 from itertools import chain
 import networkx as nx
 from networkx.utils.decorators import not_implemented_for
@@ -62,7 +63,6 @@ def is_biconnected(G):
     biconnected_components
     articulation_points
     biconnected_component_edges
-    biconnected_component_subgraphs
     is_strongly_connected
     is_weakly_connected
     is_connected
@@ -89,9 +89,12 @@ def is_biconnected(G):
 
     """
     bcc = list(biconnected_components(G))
-    if not bcc:  # No bicomponents (it could be an empty graph)
-        return False
-    return len(bcc[0]) == len(G)
+    if len(bcc) == 1:
+        return len(bcc[0]) == len(G)
+    return False  # Multiple bicomponents or No bicomponents (empty graph?)
+#    if len(bcc) == 0:  # No bicomponents (it could be an empty graph)
+#        return False
+#    return len(bcc[0]) == len(G)
 
 
 @not_implemented_for('directed')
@@ -142,7 +145,6 @@ def biconnected_component_edges(G):
     is_biconnected,
     biconnected_components,
     articulation_points,
-    biconnected_component_subgraphs
 
     Notes
     -----
@@ -236,7 +238,6 @@ def biconnected_components(G):
     is_biconnected
     articulation_points
     biconnected_component_edges
-    biconnected_component_subgraphs
 
     Notes
     -----
@@ -264,96 +265,18 @@ def biconnected_components(G):
 
 @not_implemented_for('directed')
 def biconnected_component_subgraphs(G, copy=True):
-    """Return a generator of graphs, one graph for each biconnected component
-    of the input graph.
-
-    Biconnected components are maximal subgraphs such that the removal of a
-    node (and all edges incident on that node) will not disconnect the
-    subgraph.  Note that nodes may be part of more than one biconnected
-    component.  Those nodes are articulation points, or cut vertices.  The
-    removal of articulation points will increase the number of connected
-    components of the graph.
-
-    Notice that by convention a dyad is considered a biconnected component.
-
-    Parameters
-    ----------
-    G : NetworkX Graph
-        An undirected graph.
-
-    Returns
-    -------
-    graphs : generator
-        Generator of graphs, one graph for each biconnected component.
-
-    Raises
-    ------
-    NetworkXNotImplemented :
-        If the input graph is not undirected.
-
-    Examples
-    --------
-
-    >>> G = nx.lollipop_graph(5, 1)
-    >>> print(nx.is_biconnected(G))
-    False
-    >>> bicomponents = list(nx.biconnected_component_subgraphs(G))
-    >>> len(bicomponents)
-    2
-    >>> G.add_edge(0, 5)
-    >>> print(nx.is_biconnected(G))
-    True
-    >>> bicomponents = list(nx.biconnected_component_subgraphs(G))
-    >>> len(bicomponents)
-    1
-
-    You can generate a sorted list of biconnected components, largest
-    first, using sort.
-
-    >>> G.remove_edge(0, 5)
-    >>> [len(c) for c in sorted(nx.biconnected_component_subgraphs(G),
-    ...                         key=len, reverse=True)]
-    [5, 2]
-
-    If you only want the largest connected component, it's more
-    efficient to use max instead of sort.
-
-    >>> Gc = max(nx.biconnected_component_subgraphs(G), key=len)
-
-    See Also
-    --------
-    is_biconnected
-    articulation_points
-    biconnected_component_edges
-    biconnected_components
-
-    Notes
-    -----
-    The algorithm to find articulation points and biconnected
-    components is implemented using a non-recursive depth-first-search
-    (DFS) that keeps track of the highest level that back edges reach
-    in the DFS tree.  A node `n` is an articulation point if, and only
-    if, there exists a subtree rooted at `n` such that there is no
-    back edge from any successor of `n` that links to a predecessor of
-    `n` in the DFS tree.  By keeping track of all the edges traversed
-    by the DFS we can obtain the biconnected components because all
-    edges of a bicomponent will be traversed consecutively between
-    articulation points.
-
-    Graph, node, and edge attributes are copied to the subgraphs.
-
-    References
-    ----------
-    .. [1] Hopcroft, J.; Tarjan, R. (1973).
-           "Efficient algorithms for graph manipulation".
-           Communications of the ACM 16: 372–378. doi:10.1145/362248.362272
+    """DEPRECATED: Use ``(G.subgraph(c) for c in biconnected_components(G))``
 
+           Or ``(G.subgraph(c).copy() for c in biconnected_components(G))``
     """
-    for comp_nodes in biconnected_components(G):
+    msg = "connected_component_subgraphs is deprecated and will be removed" \
+        "in 2.2. Use (G.subgraph(c).copy() for c in biconnected_components(G))"
+    _warnings.warn(msg, DeprecationWarning)
+    for c in biconnected_components(G):
         if copy:
-            yield G.subgraph(comp_nodes).copy()
+            yield G.subgraph(c).copy()
         else:
-            yield G.subgraph(comp_nodes)
+            yield G.subgraph(c)
 
 
 @not_implemented_for('directed')
@@ -402,7 +325,6 @@ def articulation_points(G):
     is_biconnected
     biconnected_components
     biconnected_component_edges
-    biconnected_component_subgraphs
 
     Notes
     -----
diff --git a/networkx/algorithms/components/connected.py b/networkx/algorithms/components/connected.py
index 2d811ad28..f7ea55587 100644
--- a/networkx/algorithms/components/connected.py
+++ b/networkx/algorithms/components/connected.py
@@ -10,6 +10,7 @@
 #          Aric Hagberg (hagberg@lanl.gov)
 #          Christopher Ellison
 """Connected components."""
+import warnings as _warnings
 import networkx as nx
 from networkx.utils.decorators import not_implemented_for
 from ...utils import arbitrary_element
@@ -76,49 +77,13 @@ def connected_components(G):
 
 @not_implemented_for('directed')
 def connected_component_subgraphs(G, copy=True):
-    """Generate connected components as subgraphs.
-
-    Parameters
-    ----------
-    G : NetworkX graph
-       An undirected graph.
-
-    copy: bool (default=True)
-      If True make a copy of the graph attributes
-
-    Returns
-    -------
-    comp : generator
-      A generator of graphs, one for each connected component of G.
-
-    Raises
-    ------
-    NetworkXNotImplemented:
-        If G is directed.
-
-    Examples
-    --------
-    >>> G = nx.path_graph(4)
-    >>> G.add_edge(5,6)
-    >>> graphs = list(nx.connected_component_subgraphs(G))
-
-    If you only want the largest connected component, it's more
-    efficient to use max instead of sort:
-
-    >>> Gc = max(nx.connected_component_subgraphs(G), key=len)
-
-    See Also
-    --------
-    connected_components
-    strongly_connected_component_subgraphs
-    weakly_connected_component_subgraphs
-
-    Notes
-    -----
-    For undirected graphs only.
-    Graph, node, and edge attributes are copied to the subgraphs by default.
+    """DEPRECATED: Use ``(G.subgraph(c) for c in connected_components(G))``
 
+           Or ``(G.subgraph(c).copy() for c in connected_components(G))``
     """
+    msg = "connected_component_subgraphs is deprecated and will be removed" \
+          "in 2.2. Use (G.subgraph(c).copy() for c in connected_components(G))"
+    _warnings.warn(msg, DeprecationWarning)
     for c in connected_components(G):
         if copy:
             yield G.subgraph(c).copy()
@@ -150,12 +115,12 @@ def number_connected_components(G):
     For undirected graphs only.
 
     """
-    return len(list(connected_components(G)))
+    return sum(1 for cc in connected_components(G))
 
 
 @not_implemented_for('directed')
 def is_connected(G):
-    """Return True if the graph is connected, false otherwise.
+    """Return True if the graph is connected, False otherwise.
 
     Parameters
     ----------
@@ -194,12 +159,12 @@ def is_connected(G):
     if len(G) == 0:
         raise nx.NetworkXPointlessConcept('Connectivity is undefined ',
                                           'for the null graph.')
-    return len(set(_plain_bfs(G, arbitrary_element(G)))) == len(G)
+    return sum(1 for node in _plain_bfs(G, arbitrary_element(G))) == len(G)
 
 
 @not_implemented_for('directed')
 def node_connected_component(G, n):
-    """Return the nodes in the component of graph containing node n.
+    """Return the set of nodes in the component of graph containing node n.
 
     Parameters
     ----------
diff --git a/networkx/algorithms/components/strongly_connected.py b/networkx/algorithms/components/strongly_connected.py
index 9b26d3a84..4c2e37dd9 100644
--- a/networkx/algorithms/components/strongly_connected.py
+++ b/networkx/algorithms/components/strongly_connected.py
@@ -11,6 +11,7 @@
 #          Christopher Ellison
 #          Ben Edwards (bedwards@cs.unm.edu)
 """Strongly connected components."""
+import warnings as _warnings
 import networkx as nx
 from networkx.utils.decorators import not_implemented_for
 
@@ -267,54 +268,18 @@ def strongly_connected_components_recursive(G):
 
 @not_implemented_for('undirected')
 def strongly_connected_component_subgraphs(G, copy=True):
-    """Generate strongly connected components as subgraphs.
-
-    Parameters
-    ----------
-    G : NetworkX Graph
-       A directed graph.
-
-    copy : boolean, optional
-        if copy is True, Graph, node, and edge attributes are copied to
-        the subgraphs.
-
-    Returns
-    -------
-    comp : generator of graphs
-      A generator of graphs, one for each strongly connected component of G.
-
-    Raises
-    ------
-    NetworkXNotImplemented:
-        If G is undirected.
-
-    Examples
-    --------
-    Generate a sorted list of strongly connected components, largest first.
-
-    >>> G = nx.cycle_graph(4, create_using=nx.DiGraph())
-    >>> nx.add_cycle(G, [10, 11, 12])
-    >>> [len(Gc) for Gc in sorted(nx.strongly_connected_component_subgraphs(G),
-    ...                         key=len, reverse=True)]
-    [4, 3]
-
-    If you only want the largest component, it's more efficient to
-    use max instead of sort.
-
-    >>> Gc = max(nx.strongly_connected_component_subgraphs(G), key=len)
-
-    See Also
-    --------
-    strongly_connected_components
-    connected_component_subgraphs
-    weakly_connected_component_subgraphs
+    """DEPRECATED: Use ``(G.subgraph(c) for c in strongly_connected_components(G))``
 
+         Or ``(G.subgraph(c).copy() for c in strongly_connected_components(G))``
     """
-    for comp in strongly_connected_components(G):
+    msg = "strongly_connected_component_subgraphs is deprecated and will be removed in 2.2" \
+        "use (G.subgraph(c).copy() for c in strongly_connected_components(G))"
+    _warnings.warn(msg, DeprecationWarning)
+    for c in strongly_connected_components(G):
         if copy:
-            yield G.subgraph(comp).copy()
+            yield G.subgraph(c).copy()
         else:
-            yield G.subgraph(comp)
+            yield G.subgraph(c)
 
 
 @not_implemented_for('undirected')
@@ -346,7 +311,7 @@ def number_strongly_connected_components(G):
     -----
     For directed graphs only.
     """
-    return len(list(strongly_connected_components(G)))
+    return sum(1 for scc in strongly_connected_components(G))
 
 
 @not_implemented_for('undirected')
@@ -434,7 +399,10 @@ def condensation(G, scc=None):
     mapping = {}
     members = {}
     C = nx.DiGraph()
-    i = 0  # required if G is empty
+    # Add mapping dict as graph attribute
+    C.graph['mapping'] = mapping
+    if len(G) == 0:
+        return C
     for i, component in enumerate(scc):
         members[i] = component
         mapping.update((n, i) for n in component)
@@ -444,6 +412,4 @@ def condensation(G, scc=None):
                      if mapping[u] != mapping[v])
     # Add a list of members (ie original nodes) to each node (ie scc) in C.
     nx.set_node_attributes(C, members, 'members')
-    # Add mapping dict as graph attribute
-    C.graph['mapping'] = mapping
     return C
diff --git a/networkx/algorithms/components/weakly_connected.py b/networkx/algorithms/components/weakly_connected.py
index eea3cfd69..012e67c48 100644
--- a/networkx/algorithms/components/weakly_connected.py
+++ b/networkx/algorithms/components/weakly_connected.py
@@ -9,6 +9,7 @@
 # Authors: Aric Hagberg (hagberg@lanl.gov)
 #          Christopher Ellison
 """Weakly connected components."""
+import warnings as _warnings
 import networkx as nx
 from networkx.utils.decorators import not_implemented_for
 
@@ -103,63 +104,23 @@ def number_weakly_connected_components(G):
     For directed graphs only.
 
     """
-    return len(list(weakly_connected_components(G)))
+    return sum(1 for wcc in weakly_connected_components(G))
 
 
 @not_implemented_for('undirected')
 def weakly_connected_component_subgraphs(G, copy=True):
-    """Generate weakly connected components as subgraphs.
-
-    Parameters
-    ----------
-    G : NetworkX graph
-        A directed graph.
-
-    copy: bool (default=True)
-        If True make a copy of the graph attributes
-
-    Returns
-    -------
-    comp : generator
-        A generator of graphs, one for each weakly connected component of G.
-
-    Raises
-    ------
-    NetworkXNotImplemented:
-        If G is undirected.
-
-    Examples
-    --------
-    Generate a sorted list of weakly connected components, largest first.
-
-    >>> G = nx.path_graph(4, create_using=nx.DiGraph())
-    >>> nx.add_path(G, [10, 11, 12])
-    >>> [len(c) for c in sorted(nx.weakly_connected_component_subgraphs(G),
-    ...                         key=len, reverse=True)]
-    [4, 3]
-
-    If you only want the largest component, it's more efficient to
-    use max instead of sort:
-
-    >>> Gc = max(nx.weakly_connected_component_subgraphs(G), key=len)
-
-    See Also
-    --------
-    weakly_connected_components
-    strongly_connected_component_subgraphs
-    connected_component_subgraphs
-
-    Notes
-    -----
-    For directed graphs only.
-    Graph, node, and edge attributes are copied to the subgraphs by default.
+    """DEPRECATED: Use ``(G.subgraph(c) for c in weakly_connected_components(G))``
 
+           Or ``(G.subgraph(c).copy() for c in weakly_connected_components(G))``
     """
-    for comp in weakly_connected_components(G):
+    msg = "weakly_connected_component_subgraphs is deprecated and will be removed in 2.2" \
+        "use (G.subgraph(c).copy() for c in weakly_connected_components(G))"
+    _warnings.warn(msg, DeprecationWarning)
+    for c in weakly_connected_components(G):
         if copy:
-            yield G.subgraph(comp).copy()
+            yield G.subgraph(c).copy()
         else:
-            yield G.subgraph(comp)
+            yield G.subgraph(c)
 
 
 @not_implemented_for('undirected')
diff --git a/networkx/classes/digraph.py b/networkx/classes/digraph.py
index 0fdc8569e..3ffc8da71 100644
--- a/networkx/classes/digraph.py
+++ b/networkx/classes/digraph.py
@@ -136,8 +136,10 @@ class DiGraph(Graph):
     >>> G.edges[1, 2]['weight'] = 4
 
     Warning: we protect the graph data structure by making `G.edges[1, 2]` a
-    read-only dict-like structure. Use 2 sets of brackets to add/change
-    data attributes. (For multigraphs: `MG.edges[u, v, key][name] = value`).
+    read-only dict-like structure. However, you can assign to attributes
+    in e.g. `G.edges[1, 2]`. Thus, use 2 sets of brackets to add/change
+    data attributes: `G.edges[1, 2]['weight'] = 4`
+    (For multigraphs: `MG.edges[u, v, key][name] = value`).
 
     **Shortcuts:**
 
diff --git a/networkx/classes/graph.py b/networkx/classes/graph.py
index b5cf78528..12e9b6aa8 100644
--- a/networkx/classes/graph.py
+++ b/networkx/classes/graph.py
@@ -145,9 +145,11 @@ class Graph(object):
     >>> G[1][2]['weight'] = 4.7
     >>> G.edges[1, 2]['weight'] = 4
 
-    Warning: we protect the graph data structure by making `G.edges[1, 2]` a
-    read-only dict-like structure. Use 2 sets of brackets to add/change
-    data attributes. (For multigraphs: `MG.edges[u, v, key][name] = value`).
+    Warning: we protect the graph data structure by making `G.edges` a
+    read-only dict-like structure. However, you can assign to attributes
+    in e.g. `G.edges[1, 2]`. Thus, use 2 sets of brackets to add/change
+    data attributes: `G.edges[1, 2]['weight'] = 4`
+    (For multigraphs: `MG.edges[u, v, key][name] = value`).
 
     **Shortcuts:**
 
diff --git a/networkx/classes/multidigraph.py b/networkx/classes/multidigraph.py
index 68dbb4333..b9849d217 100644
--- a/networkx/classes/multidigraph.py
+++ b/networkx/classes/multidigraph.py
@@ -141,8 +141,10 @@ class MultiDiGraph(MultiGraph, DiGraph):
     >>> G.edges[1, 2, 0]['weight'] = 4
 
     Warning: we protect the graph data structure by making `G.edges[1, 2]` a
-    read-only dict-like structure. Use 2 sets of brackets to add/change
-    data attributes. (For multigraphs: `MG.edges[u, v, key][name] = value`).
+    read-only dict-like structure. However, you can assign to attributes
+    in e.g. `G.edges[1, 2]`. Thus, use 2 sets of brackets to add/change
+    data attributes: `G.edges[1, 2]['weight'] = 4`
+    (For multigraphs: `MG.edges[u, v, key][name] = value`).
 
     **Shortcuts:**
 
diff --git a/networkx/classes/multigraph.py b/networkx/classes/multigraph.py
index 9e5e9c1bd..ba705c5c7 100644
--- a/networkx/classes/multigraph.py
+++ b/networkx/classes/multigraph.py
@@ -140,8 +140,10 @@ class MultiGraph(Graph):
     >>> G.edges[1, 2, 0]['weight'] = 4
 
     Warning: we protect the graph data structure by making `G.edges[1, 2]` a
-    read-only dict-like structure. Use 2 sets of brackets to add/change
-    data attributes. (For multigraphs: `MG.edges[u, v, key][name] = value`).
+    read-only dict-like structure. However, you can assign to attributes
+    in e.g. `G.edges[1, 2]`. Thus, use 2 sets of brackets to add/change
+    data attributes: `G.edges[1, 2]['weight'] = 4`
+    (For multigraphs: `MG.edges[u, v, key][name] = value`).
 
     **Shortcuts:**
 
@@ -762,9 +764,11 @@ class MultiGraph(Graph):
         {'weight': 7}
 
         Warning: we protect the graph data structure by making
-        `G.edges[1, 2, key]` and `G[1][2][key]` read-only dict-like
-        structures. You need to specify all edge info to assign to
-        the edge data associated with that edge.
+        `G.edges` and `G[1][2]` read-only dict-like structures.
+        However, you can assign values to attributes in e.g.
+        `G.edges[1, 2, 'a']` or `G[1][2]['a']` using an additional
+        bracket as shown next. You need to specify all edge info
+        to assign to the edge data associated with an edge.
 
         >>> G[0][1]['a']['weight'] = 10
         >>> G.edges[0, 1, 'a']['weight'] = 10
diff --git a/networkx/convert_matrix.py b/networkx/convert_matrix.py
index b1c7f6193..67bca77f6 100644
--- a/networkx/convert_matrix.py
+++ b/networkx/convert_matrix.py
@@ -27,7 +27,6 @@ See Also
 nx_agraph, nx_pydot
 """
 
-import warnings as _warnings
 import itertools
 import networkx as nx
 from networkx.convert import _prep_create_using
diff --git a/tools/travis/build_docs.sh b/tools/travis/build_docs.sh
index 294a348d5..eb4899037 100755
--- a/tools/travis/build_docs.sh
+++ b/tools/travis/build_docs.sh
@@ -6,7 +6,6 @@ pip install --retries 3 -q -r requirements/doc.txt
 export SPHINXCACHE=$HOME/.cache/sphinx
 cd doc
 make html
-make doctest
 make latexpdf
 cd ..
 


Test patch:
diff --git a/networkx/algorithms/components/tests/test_attracting.py b/networkx/algorithms/components/tests/test_attracting.py
index 92b4f9e2f..953fd97fc 100644
--- a/networkx/algorithms/components/tests/test_attracting.py
+++ b/networkx/algorithms/components/tests/test_attracting.py
@@ -15,6 +15,8 @@ class TestAttractingComponents(object):
         self.G3 = nx.DiGraph()
         self.G3.add_edges_from([(0, 1), (1, 2), (2, 1), (0, 3), (3, 4), (4, 3)])
 
+        self.G4 = nx.DiGraph()
+
     def test_attracting_components(self):
         ac = list(nx.attracting_components(self.G1))
         assert_true({2} in ac)
@@ -31,10 +33,14 @@ class TestAttractingComponents(object):
         assert_true((3, 4) in ac)
         assert_equal(len(ac), 2)
 
+        ac = list(nx.attracting_components(self.G4))
+        assert_equal(ac, [])
+
     def test_number_attacting_components(self):
         assert_equal(nx.number_attracting_components(self.G1), 3)
         assert_equal(nx.number_attracting_components(self.G2), 1)
         assert_equal(nx.number_attracting_components(self.G3), 2)
+        assert_equal(nx.number_attracting_components(self.G4), 0)
 
     def test_is_attracting_component(self):
         assert_false(nx.is_attracting_component(self.G1))
@@ -42,10 +48,12 @@ class TestAttractingComponents(object):
         assert_false(nx.is_attracting_component(self.G3))
         g2 = self.G3.subgraph([1, 2])
         assert_true(nx.is_attracting_component(g2))
+        assert_false(nx.is_attracting_component(self.G4))
 
     def test_connected_raise(self):
         G=nx.Graph()
         assert_raises(NetworkXNotImplemented, nx.attracting_components, G)
         assert_raises(NetworkXNotImplemented, nx.number_attracting_components, G)
         assert_raises(NetworkXNotImplemented, nx.is_attracting_component, G)
+        # deprecated
         assert_raises(NetworkXNotImplemented, nx.attracting_component_subgraphs, G)
diff --git a/networkx/algorithms/components/tests/test_biconnected.py b/networkx/algorithms/components/tests/test_biconnected.py
index faf216f4c..54612bc48 100644
--- a/networkx/algorithms/components/tests/test_biconnected.py
+++ b/networkx/algorithms/components/tests/test_biconnected.py
@@ -71,6 +71,7 @@ def test_biconnected_components_cycle():
     answer = [{0, 1, 2}, {1, 3, 4}]
     assert_components_equal(list(nx.biconnected_components(G)), answer)
 
+# deprecated
 def test_biconnected_component_subgraphs_cycle():
     G=nx.cycle_graph(3)
     nx.add_cycle(G, [1, 3, 4, 5])
@@ -169,10 +170,18 @@ def test_biconnected_eppstein():
     bcc = list(nx.biconnected_components(G2))
     assert_components_equal(bcc, answer_G2)
 
+def test_null_graph():
+    G = nx.Graph()
+    assert_false(nx.is_biconnected(G))
+    assert_equal(list(nx.biconnected_components(G)), [])
+    assert_equal(list(nx.biconnected_component_edges(G)), [])
+    assert_equal(list(nx.articulation_points(G)), [])
+
 def test_connected_raise():
     DG = nx.DiGraph()
     assert_raises(NetworkXNotImplemented, nx.biconnected_components, DG)
-    assert_raises(NetworkXNotImplemented, nx.biconnected_component_subgraphs, DG)
     assert_raises(NetworkXNotImplemented, nx.biconnected_component_edges, DG)
     assert_raises(NetworkXNotImplemented, nx.articulation_points, DG)
     assert_raises(NetworkXNotImplemented, nx.is_biconnected, DG)
+    # deprecated
+    assert_raises(NetworkXNotImplemented, nx.biconnected_component_subgraphs, DG)
diff --git a/networkx/algorithms/components/tests/test_connected.py b/networkx/algorithms/components/tests/test_connected.py
index 168f561a7..99f58386e 100644
--- a/networkx/algorithms/components/tests/test_connected.py
+++ b/networkx/algorithms/components/tests/test_connected.py
@@ -41,6 +41,10 @@ class TestConnected:
         C = [[0, 1, 2], [3, 4]]
         self.gc.append((G, C))
 
+        G = nx.DiGraph()
+        C = []
+        self.gc.append((G, C))
+
 
     def test_connected_components(self):
         cc = nx.connected_components
@@ -72,6 +76,7 @@ class TestConnected:
         C = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
         assert_equal(ncc(G, 1), C)
 
+    # deprecated
     def test_connected_component_subgraphs(self):
         wcc = nx.weakly_connected_component_subgraphs
         cc = nx.connected_component_subgraphs
@@ -90,7 +95,8 @@ class TestConnected:
     def test_connected_raise(self):
         assert_raises(NetworkXNotImplemented, nx.connected_components, self.DG)
         assert_raises(NetworkXNotImplemented, nx.number_connected_components, self.DG)
-        assert_raises(NetworkXNotImplemented, nx.connected_component_subgraphs, self.DG)
         assert_raises(NetworkXNotImplemented, nx.node_connected_component, self.DG,1)
         assert_raises(NetworkXNotImplemented, nx.is_connected, self.DG)
         assert_raises(nx.NetworkXPointlessConcept, nx.is_connected, nx.Graph())
+        # deprecated
+        assert_raises(NetworkXNotImplemented, nx.connected_component_subgraphs, self.DG)
diff --git a/networkx/algorithms/components/tests/test_strongly_connected.py b/networkx/algorithms/components/tests/test_strongly_connected.py
index 0886cb91b..5468aec72 100644
--- a/networkx/algorithms/components/tests/test_strongly_connected.py
+++ b/networkx/algorithms/components/tests/test_strongly_connected.py
@@ -67,6 +67,7 @@ class TestStronglyConnected:
             else:
                 assert_false(nx.is_strongly_connected(G))
 
+    # deprecated
     def test_strongly_connected_component_subgraphs(self):
         scc = nx.strongly_connected_component_subgraphs
         for G, C in self.gc:
@@ -134,12 +135,21 @@ class TestStronglyConnected:
         for n, d in cG.nodes(data=True):
             assert_equal(set(C[n]), cG.nodes[n]['members'])
 
+    def test_null_graph(self):
+        G=nx.DiGraph()
+        assert_equal(list(nx.strongly_connected_components(G)), [])
+        assert_equal(list(nx.kosaraju_strongly_connected_components(G)), [])
+        assert_equal(list(nx.strongly_connected_components_recursive(G)), [])
+        assert_equal(len(nx.condensation(G)), 0)
+        assert_raises(nx.NetworkXPointlessConcept, nx.is_strongly_connected, nx.DiGraph())
+
     def test_connected_raise(self):
         G=nx.Graph()
         assert_raises(NetworkXNotImplemented, nx.strongly_connected_components, G)
         assert_raises(NetworkXNotImplemented, nx.kosaraju_strongly_connected_components, G)
         assert_raises(NetworkXNotImplemented, nx.strongly_connected_components_recursive, G)
-        assert_raises(NetworkXNotImplemented, nx.strongly_connected_component_subgraphs, G)
         assert_raises(NetworkXNotImplemented, nx.is_strongly_connected, G)
         assert_raises(nx.NetworkXPointlessConcept, nx.is_strongly_connected, nx.DiGraph())
         assert_raises(NetworkXNotImplemented, nx.condensation, G)
+        # deprecated
+        assert_raises(NetworkXNotImplemented, nx.strongly_connected_component_subgraphs, G)
diff --git a/networkx/algorithms/components/tests/test_subgraph_copies.py b/networkx/algorithms/components/tests/test_subgraph_copies.py
index b6c8dc611..9acedba2d 100644
--- a/networkx/algorithms/components/tests/test_subgraph_copies.py
+++ b/networkx/algorithms/components/tests/test_subgraph_copies.py
@@ -4,6 +4,9 @@ from copy import deepcopy
 from nose.tools import assert_equal
 import networkx as nx
 
+# deprecated in 2.1 for removal in 2.2
+
+
 class TestSubgraphAttributesDicts:
 
     def setUp(self):
diff --git a/networkx/algorithms/components/tests/test_weakly_connected.py b/networkx/algorithms/components/tests/test_weakly_connected.py
index ead698971..8c993debc 100644
--- a/networkx/algorithms/components/tests/test_weakly_connected.py
+++ b/networkx/algorithms/components/tests/test_weakly_connected.py
@@ -47,6 +47,7 @@ class TestWeaklyConnected:
             c = nx.number_connected_components(U)
             assert_equal(w, c)
 
+    # deprecated
     def test_weakly_connected_component_subgraphs(self):
         wcc = nx.weakly_connected_component_subgraphs
         cc = nx.connected_component_subgraphs
@@ -61,9 +62,16 @@ class TestWeaklyConnected:
             U = G.to_undirected()
             assert_equal(nx.is_weakly_connected(G), nx.is_connected(U))
 
+    def test_null_graph(self):
+        G=nx.DiGraph()
+        assert_equal(list(nx.weakly_connected_components(G)), [])
+        assert_equal(nx.number_weakly_connected_components(G), 0)
+        assert_raises(nx.NetworkXPointlessConcept, nx.is_weakly_connected, G)
+
     def test_connected_raise(self):
         G=nx.Graph()
         assert_raises(NetworkXNotImplemented,nx.weakly_connected_components, G)
         assert_raises(NetworkXNotImplemented,nx.number_weakly_connected_components, G)
-        assert_raises(NetworkXNotImplemented,nx.weakly_connected_component_subgraphs, G)
         assert_raises(NetworkXNotImplemented,nx.is_weakly_connected, G)
+        # deprecated
+        assert_raises(NetworkXNotImplemented,nx.weakly_connected_component_subgraphs, G)
diff --git a/networkx/algorithms/shortest_paths/weighted.py b/networkx/algorithms/shortest_paths/weighted.py
index 3403393ba..16099b451 100644
--- a/networkx/algorithms/shortest_paths/weighted.py
+++ b/networkx/algorithms/shortest_paths/weighted.py
@@ -19,7 +19,6 @@ from heapq import heappush, heappop
 from itertools import count
 import networkx as nx
 from networkx.utils import generate_unique_node
-import warnings as _warnings
 
 
 __all__ = ['dijkstra_path',