'Add an edge between u and v.
The nodes u and v will be automatically added if they are
not already in the graph.
Edge attributes can be specified with keywords or by directly
accessing the edge\'s attribute dictionary. See examples below.
Parameters
u, v : nodes
Nodes can be, for example, strings or numbers.
Nodes must be hashable (and not None) Python objects.
attr : keyword arguments, optional
Edge data (or labels or objects) can be assigned using
keyword arguments.
See Also
add_edges_from : add a collection of edges
Notes
Adding an edge that already exists updates the edge data.
Many NetworkX algorithms designed for weighted graphs use as
the edge weight a numerical value assigned to a keyword
which by default is \'weight\'.
Examples
The following all add the edge e=(1, 2) to graph G:
>>> G = nx.Graph()   # or DiGraph, MultiGraph, MultiDiGraph, etc
>>> e = (1, 2)
>>> G.add_edge(1, 2)           # explicit two-node form
>>> G.add_edge(*e)             # single edge as tuple of two nodes
>>> G.add_edges_from( [(1, 2)] ) # add edges from iterable container
Associate data to edges using keywords:
>>> G.add_edge(1, 2, weight=3)
>>> G.add_edge(1, 3, weight=7, capacity=15, length=342.7)
For non-string associations, directly access the edge\'s attribute
dictionary.
>>> G.add_edge(1, 2)
>>> G[1][2].update({0: 5})'

def add_edge(self, u, v, **attr):

    if (u not in self._succ):
        self._succ[u] = self.adjlist_inner_dict_factory()
        self._pred[u] = self.adjlist_inner_dict_factory()
        self._node[u] = {}
    if (v not in self._succ):
        self._succ[v] = self.adjlist_inner_dict_factory()
        self._pred[v] = self.adjlist_inner_dict_factory()
        self._node[v] = {}
    datadict = self._adj[u].get(v, self.edge_attr_dict_factory())
    datadict.update(attr)
    self._succ[u][v] = datadict
    self._pred[v][u] = datadict
