Repository: networkx/networkx

Issue:
Deprecation warnings for G.node and G.edge?
@dschult , @hagberg While trying to get scikit-image working with 2.0, I've started wondering if we should provide ``G.node`` and ``G.edge`` for backward compatibility until we release 2.1 or so.

Here is the scikit-image PR:
https://github.com/scikit-image/scikit-image/pull/2766


Discussion:
That seems like a reasonable idea.  
I think if we leave it for v2.0 it will be hard to change it for v2.1 where people don't expect strong changes in API.  But, I am fine with leaving ```G.node``` and ```G.edge``` until v?.? determined at a later date.  I suppose we could keep ```nodes_iter/edges_iter``` also pointing to ```nodes/edges``` but I'd prefer to have them change to the non-```_iter``` version (which works with v1.x code too).

Either way we might want to advertise a way to make graphs from v2.0 look like v1.x graphs. That way people can use code that will work for either. I guess that should be put into the migration document.

The other major change is that copy/subgraph/reverse/edge_subgraph have changed the level of deep-ness of their copying.  I'm not sure what the best way of handling that is.  It depends whether their code needs a certain level of deep-nees or not. Most of the time the v2 deep-nees works: a simple ```.copy()``` should be enough. But if their graph has edge data that is a container and they change it on the subgraph, they will need a ```deepcopy```. Note too that using ```deepcopy``` on a graphview will copy both the view object and the underlying graph object. 

Here is some code to make v2.x look like v1.x except for deep-ness of copies.
```
    if not hasattr(G, "nodes_iter"):
        G.nodes_iter = G.nodes    # or make them remove _iter from their code.
        G.edges_iter = G.edges   # or make them remove _iter from their code.
        # same for G.degree_iter, G.adjacency_iter, G.adjacency_list, G.neighbors_iter

        G.node = G.nodes
        G.edge = G.adj
        def subgraph(self, nbunch):
            induced_nodes = nx.filters.show_nodes(self.nbunch_iter(nbunch))
            return nx.graphviews.SubGraph(self, induced_nodes).copy()               # Notice the .copy()
        G.subgraph = subgraph
```

If we re-introduce ```G.node``` and ```G.edge``` and tell people to remove the ```_iter``` from their code I think we don't need the above conversion. The only compatibility issue left is the level of deep-ness of copy/subgraph/reverse.  We can say: if in doubt, deepcopy.  But I suspect most of the time they shouldn't deepcopy.
I don't know a way to make deprecation warnings on use of an attribute. 

Perhaps we should just leave them in the API long term...
I haven't checked whether this works, but I was thinking we could do something like:
```
    @property
    def node(self):
        return self._node

    @property
    def edge(self):
        return self._adj

    def nodes_iter(self, data=False):
        return list(self.nodes(data))

    def edges_iter(self, *args, **kwargs):
        return list(self.edges(*args, **kwargs))
```

But with warnings like this for all four methods (I didn't want to cluster the above snippets):

```
    @property
    def node(self):
        """DEPRECATED: Replaced by ``nodes``."""
        msg = "node is deprecated and will be removed" \
            "in 2.1, use nodes instead."
        _warnings.warn(msg, DeprecationWarning)
        return self._node
```

Do you think something like that might work?  I can make a PR this evening and test it with ``scikit-image``.
Nice use of @property.    :)
There are other ```_iter``` functions too. If these work we could do the same for them.

Q: will the scikit-image code then produce deprecation warnings when they use code that works for both v1.x and v2?  How do we best serve packages which want to support old and new versions of our code?

Resolving patch:
diff --git a/networkx/classes/graph.py b/networkx/classes/graph.py
--- a/networkx/classes/graph.py
+++ b/networkx/classes/graph.py
@@ -711,6 +711,9 @@ def nodes(self):
         self.__dict__['nodes'] = nodes
         return nodes
 
+    # for backwards compatibility with 1.x, will be removed for 3.x
+    node = nodes
+
     def number_of_nodes(self):
         """Return the number of nodes in the graph.
 


Test patch:
diff --git a/networkx/classes/tests/test_graph.py b/networkx/classes/tests/test_graph.py
--- a/networkx/classes/tests/test_graph.py
+++ b/networkx/classes/tests/test_graph.py
@@ -9,6 +9,12 @@
 from networkx.testing.utils import *
 
 
+def test_deprecated():
+    # for backwards compatibility with 1.x, will be removed for 3.x
+    G = nx.complete_graph(3)
+    assert_equal(G.node, {0: {}, 1: {}, 2: {}})
+
+
 class BaseGraphTester(object):
     """ Tests for data-structure independent graph class features."""