using for loop to install conda package
This commit is contained in:
14
.CondaPkg/env/Lib/site-packages/networkx/classes/__init__.py
vendored
Normal file
14
.CondaPkg/env/Lib/site-packages/networkx/classes/__init__.py
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
from .graph import Graph
|
||||
from .digraph import DiGraph
|
||||
from .multigraph import MultiGraph
|
||||
from .multidigraph import MultiDiGraph
|
||||
from .backends import _dispatch
|
||||
|
||||
from .function import *
|
||||
|
||||
from networkx.classes import filters
|
||||
|
||||
from networkx.classes import coreviews
|
||||
from networkx.classes import graphviews
|
||||
from networkx.classes import reportviews
|
||||
from networkx.classes import backends
|
||||
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/backends.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/backends.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/coreviews.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/coreviews.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/digraph.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/digraph.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/filters.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/filters.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/function.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/function.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/graph.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/graph.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/graphviews.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/graphviews.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/multidigraph.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/multidigraph.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/multigraph.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/multigraph.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/reportviews.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/__pycache__/reportviews.cpython-311.pyc
vendored
Normal file
Binary file not shown.
243
.CondaPkg/env/Lib/site-packages/networkx/classes/backends.py
vendored
Normal file
243
.CondaPkg/env/Lib/site-packages/networkx/classes/backends.py
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
"""
|
||||
Code to support various backends in a plugin dispatch architecture.
|
||||
|
||||
Create a Dispatcher
|
||||
-------------------
|
||||
|
||||
To be a valid plugin, a package must register an entry_point
|
||||
of `networkx.plugins` with a key pointing to the handler.
|
||||
|
||||
For example::
|
||||
|
||||
entry_points={'networkx.plugins': 'sparse = networkx_plugin_sparse'}
|
||||
|
||||
The plugin must create a Graph-like object which contains an attribute
|
||||
``__networkx_plugin__`` with a value of the entry point name.
|
||||
|
||||
Continuing the example above::
|
||||
|
||||
class WrappedSparse:
|
||||
__networkx_plugin__ = "sparse"
|
||||
...
|
||||
|
||||
When a dispatchable NetworkX algorithm encounters a Graph-like object
|
||||
with a ``__networkx_plugin__`` attribute, it will look for the associated
|
||||
dispatch object in the entry_points, load it, and dispatch the work to it.
|
||||
|
||||
|
||||
Testing
|
||||
-------
|
||||
To assist in validating the backend algorithm implementations, if an
|
||||
environment variable ``NETWORKX_GRAPH_CONVERT`` is set to a registered
|
||||
plugin keys, the dispatch machinery will automatically convert regular
|
||||
networkx Graphs and DiGraphs to the backend equivalent by calling
|
||||
``<backend dispatcher>.convert_from_nx(G, weight=weight, name=name)``.
|
||||
|
||||
The converted object is then passed to the backend implementation of
|
||||
the algorithm. The result is then passed to
|
||||
``<backend dispatcher>.convert_to_nx(result, name=name)`` to convert back
|
||||
to a form expected by the NetworkX tests.
|
||||
|
||||
By defining ``convert_from_nx`` and ``convert_to_nx`` methods and setting
|
||||
the environment variable, NetworkX will automatically route tests on
|
||||
dispatchable algorithms to the backend, allowing the full networkx test
|
||||
suite to be run against the backend implementation.
|
||||
|
||||
Example pytest invocation::
|
||||
|
||||
NETWORKX_GRAPH_CONVERT=sparse pytest --pyargs networkx
|
||||
|
||||
Dispatchable algorithms which are not implemented by the backend
|
||||
will cause a ``pytest.xfail()``, giving some indication that not all
|
||||
tests are working, while avoiding causing an explicit failure.
|
||||
|
||||
A special ``on_start_tests(items)`` function may be defined by the backend.
|
||||
It will be called with the list of NetworkX tests discovered. Each item
|
||||
is a test object that can be marked as xfail if the backend does not support
|
||||
the test using `item.add_marker(pytest.mark.xfail(reason=...))`.
|
||||
"""
|
||||
import functools
|
||||
import inspect
|
||||
import os
|
||||
import sys
|
||||
from importlib.metadata import entry_points
|
||||
|
||||
from ..exception import NetworkXNotImplemented
|
||||
|
||||
__all__ = ["_dispatch", "_mark_tests"]
|
||||
|
||||
|
||||
class PluginInfo:
|
||||
"""Lazily loaded entry_points plugin information"""
|
||||
|
||||
def __init__(self):
|
||||
self._items = None
|
||||
|
||||
def __bool__(self):
|
||||
return len(self.items) > 0
|
||||
|
||||
@property
|
||||
def items(self):
|
||||
if self._items is None:
|
||||
if sys.version_info < (3, 10):
|
||||
self._items = entry_points()["networkx.plugins"]
|
||||
else:
|
||||
self._items = entry_points(group="networkx.plugins")
|
||||
return self._items
|
||||
|
||||
def __contains__(self, name):
|
||||
if sys.version_info < (3, 10):
|
||||
return len([ep for ep in self.items if ep.name == name]) > 0
|
||||
return name in self.items.names
|
||||
|
||||
def __getitem__(self, name):
|
||||
if sys.version_info < (3, 10):
|
||||
return [ep for ep in self.items if ep.name == name][0]
|
||||
return self.items[name]
|
||||
|
||||
|
||||
plugins = PluginInfo()
|
||||
_registered_algorithms = {}
|
||||
|
||||
|
||||
def _register_algo(name, wrapped_func):
|
||||
if name in _registered_algorithms:
|
||||
raise KeyError(f"Algorithm already exists in dispatch registry: {name}")
|
||||
_registered_algorithms[name] = wrapped_func
|
||||
wrapped_func.dispatchname = name
|
||||
|
||||
|
||||
def _dispatch(func=None, *, name=None):
|
||||
"""Dispatches to a backend algorithm
|
||||
when the first argument is a backend graph-like object.
|
||||
"""
|
||||
# Allow any of the following decorator forms:
|
||||
# - @_dispatch
|
||||
# - @_dispatch()
|
||||
# - @_dispatch("override_name")
|
||||
# - @_dispatch(name="override_name")
|
||||
if func is None:
|
||||
if name is None:
|
||||
return _dispatch
|
||||
return functools.partial(_dispatch, name=name)
|
||||
if isinstance(func, str):
|
||||
return functools.partial(_dispatch, name=func)
|
||||
# If name not provided, use the name of the function
|
||||
if name is None:
|
||||
name = func.__name__
|
||||
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwds):
|
||||
if args:
|
||||
graph = args[0]
|
||||
else:
|
||||
try:
|
||||
graph = kwds["G"]
|
||||
except KeyError:
|
||||
raise TypeError(f"{name}() missing positional argument: 'G'") from None
|
||||
if hasattr(graph, "__networkx_plugin__") and plugins:
|
||||
plugin_name = graph.__networkx_plugin__
|
||||
if plugin_name in plugins:
|
||||
backend = plugins[plugin_name].load()
|
||||
if hasattr(backend, name):
|
||||
return getattr(backend, name).__call__(*args, **kwds)
|
||||
else:
|
||||
raise NetworkXNotImplemented(
|
||||
f"'{name}' not implemented by {plugin_name}"
|
||||
)
|
||||
return func(*args, **kwds)
|
||||
|
||||
# Keep a handle to the original function to use when testing
|
||||
# the dispatch mechanism internally
|
||||
wrapper._orig_func = func
|
||||
|
||||
_register_algo(name, wrapper)
|
||||
return wrapper
|
||||
|
||||
|
||||
def test_override_dispatch(func=None, *, name=None):
|
||||
"""Auto-converts the first argument into the backend equivalent,
|
||||
causing the dispatching mechanism to trigger for every
|
||||
decorated algorithm."""
|
||||
if func is None:
|
||||
if name is None:
|
||||
return test_override_dispatch
|
||||
return functools.partial(test_override_dispatch, name=name)
|
||||
if isinstance(func, str):
|
||||
return functools.partial(test_override_dispatch, name=func)
|
||||
# If name not provided, use the name of the function
|
||||
if name is None:
|
||||
name = func.__name__
|
||||
|
||||
sig = inspect.signature(func)
|
||||
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwds):
|
||||
backend = plugins[plugin_name].load()
|
||||
if not hasattr(backend, name):
|
||||
if plugin_name == "nx-loopback":
|
||||
raise NetworkXNotImplemented(
|
||||
f"'{name}' not found in {backend.__class__.__name__}"
|
||||
)
|
||||
pytest.xfail(f"'{name}' not implemented by {plugin_name}")
|
||||
bound = sig.bind(*args, **kwds)
|
||||
bound.apply_defaults()
|
||||
if args:
|
||||
graph, *args = args
|
||||
else:
|
||||
try:
|
||||
graph = kwds.pop("G")
|
||||
except KeyError:
|
||||
raise TypeError(f"{name}() missing positional argument: 'G'") from None
|
||||
# Convert graph into backend graph-like object
|
||||
# Include the weight label, if provided to the algorithm
|
||||
weight = None
|
||||
if "weight" in bound.arguments:
|
||||
weight = bound.arguments["weight"]
|
||||
elif "data" in bound.arguments and "default" in bound.arguments:
|
||||
# This case exists for several MultiGraph edge algorithms
|
||||
if isinstance(bound.arguments["data"], str):
|
||||
weight = bound.arguments["data"]
|
||||
elif bound.arguments["data"]:
|
||||
weight = "weight"
|
||||
graph = backend.convert_from_nx(graph, weight=weight, name=name)
|
||||
result = getattr(backend, name).__call__(graph, *args, **kwds)
|
||||
return backend.convert_to_nx(result, name=name)
|
||||
|
||||
wrapper._orig_func = func
|
||||
_register_algo(name, wrapper)
|
||||
return wrapper
|
||||
|
||||
|
||||
# Check for auto-convert testing
|
||||
# This allows existing NetworkX tests to be run against a backend
|
||||
# implementation without any changes to the testing code. The only
|
||||
# required change is to set an environment variable prior to running
|
||||
# pytest.
|
||||
if os.environ.get("NETWORKX_GRAPH_CONVERT"):
|
||||
plugin_name = os.environ["NETWORKX_GRAPH_CONVERT"]
|
||||
if not plugins:
|
||||
raise Exception("No registered networkx.plugins entry_points")
|
||||
if plugin_name not in plugins:
|
||||
raise Exception(
|
||||
f"No registered networkx.plugins entry_point named {plugin_name}"
|
||||
)
|
||||
|
||||
try:
|
||||
import pytest
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
f"Missing pytest, which is required when using NETWORKX_GRAPH_CONVERT"
|
||||
)
|
||||
|
||||
# Override `dispatch` for testing
|
||||
_dispatch = test_override_dispatch
|
||||
|
||||
|
||||
def _mark_tests(items):
|
||||
"""Allow backend to mark tests (skip or xfail) if they aren't able to correctly handle them"""
|
||||
if os.environ.get("NETWORKX_GRAPH_CONVERT"):
|
||||
plugin_name = os.environ["NETWORKX_GRAPH_CONVERT"]
|
||||
backend = plugins[plugin_name].load()
|
||||
if hasattr(backend, "on_start_tests"):
|
||||
getattr(backend, "on_start_tests")(items)
|
||||
367
.CondaPkg/env/Lib/site-packages/networkx/classes/coreviews.py
vendored
Normal file
367
.CondaPkg/env/Lib/site-packages/networkx/classes/coreviews.py
vendored
Normal file
@@ -0,0 +1,367 @@
|
||||
"""Views of core data structures such as nested Mappings (e.g. dict-of-dicts).
|
||||
These ``Views`` often restrict element access, with either the entire view or
|
||||
layers of nested mappings being read-only.
|
||||
"""
|
||||
from collections.abc import Mapping
|
||||
|
||||
__all__ = [
|
||||
"AtlasView",
|
||||
"AdjacencyView",
|
||||
"MultiAdjacencyView",
|
||||
"UnionAtlas",
|
||||
"UnionAdjacency",
|
||||
"UnionMultiInner",
|
||||
"UnionMultiAdjacency",
|
||||
"FilterAtlas",
|
||||
"FilterAdjacency",
|
||||
"FilterMultiInner",
|
||||
"FilterMultiAdjacency",
|
||||
]
|
||||
|
||||
|
||||
class AtlasView(Mapping):
|
||||
"""An AtlasView is a Read-only Mapping of Mappings.
|
||||
|
||||
It is a View into a dict-of-dict data structure.
|
||||
The inner level of dict is read-write. But the
|
||||
outer level is read-only.
|
||||
|
||||
See Also
|
||||
========
|
||||
AdjacencyView: View into dict-of-dict-of-dict
|
||||
MultiAdjacencyView: View into dict-of-dict-of-dict-of-dict
|
||||
"""
|
||||
|
||||
__slots__ = ("_atlas",)
|
||||
|
||||
def __getstate__(self):
|
||||
return {"_atlas": self._atlas}
|
||||
|
||||
def __setstate__(self, state):
|
||||
self._atlas = state["_atlas"]
|
||||
|
||||
def __init__(self, d):
|
||||
self._atlas = d
|
||||
|
||||
def __len__(self):
|
||||
return len(self._atlas)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._atlas)
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._atlas[key]
|
||||
|
||||
def copy(self):
|
||||
return {n: self[n].copy() for n in self._atlas}
|
||||
|
||||
def __str__(self):
|
||||
return str(self._atlas) # {nbr: self[nbr] for nbr in self})
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.__class__.__name__}({self._atlas!r})"
|
||||
|
||||
|
||||
class AdjacencyView(AtlasView):
|
||||
"""An AdjacencyView is a Read-only Map of Maps of Maps.
|
||||
|
||||
It is a View into a dict-of-dict-of-dict data structure.
|
||||
The inner level of dict is read-write. But the
|
||||
outer levels are read-only.
|
||||
|
||||
See Also
|
||||
========
|
||||
AtlasView: View into dict-of-dict
|
||||
MultiAdjacencyView: View into dict-of-dict-of-dict-of-dict
|
||||
"""
|
||||
|
||||
__slots__ = () # Still uses AtlasView slots names _atlas
|
||||
|
||||
def __getitem__(self, name):
|
||||
return AtlasView(self._atlas[name])
|
||||
|
||||
def copy(self):
|
||||
return {n: self[n].copy() for n in self._atlas}
|
||||
|
||||
|
||||
class MultiAdjacencyView(AdjacencyView):
|
||||
"""An MultiAdjacencyView is a Read-only Map of Maps of Maps of Maps.
|
||||
|
||||
It is a View into a dict-of-dict-of-dict-of-dict data structure.
|
||||
The inner level of dict is read-write. But the
|
||||
outer levels are read-only.
|
||||
|
||||
See Also
|
||||
========
|
||||
AtlasView: View into dict-of-dict
|
||||
AdjacencyView: View into dict-of-dict-of-dict
|
||||
"""
|
||||
|
||||
__slots__ = () # Still uses AtlasView slots names _atlas
|
||||
|
||||
def __getitem__(self, name):
|
||||
return AdjacencyView(self._atlas[name])
|
||||
|
||||
def copy(self):
|
||||
return {n: self[n].copy() for n in self._atlas}
|
||||
|
||||
|
||||
class UnionAtlas(Mapping):
|
||||
"""A read-only union of two atlases (dict-of-dict).
|
||||
|
||||
The two dict-of-dicts represent the inner dict of
|
||||
an Adjacency: `G.succ[node]` and `G.pred[node]`.
|
||||
The inner level of dict of both hold attribute key:value
|
||||
pairs and is read-write. But the outer level is read-only.
|
||||
|
||||
See Also
|
||||
========
|
||||
UnionAdjacency: View into dict-of-dict-of-dict
|
||||
UnionMultiAdjacency: View into dict-of-dict-of-dict-of-dict
|
||||
"""
|
||||
|
||||
__slots__ = ("_succ", "_pred")
|
||||
|
||||
def __getstate__(self):
|
||||
return {"_succ": self._succ, "_pred": self._pred}
|
||||
|
||||
def __setstate__(self, state):
|
||||
self._succ = state["_succ"]
|
||||
self._pred = state["_pred"]
|
||||
|
||||
def __init__(self, succ, pred):
|
||||
self._succ = succ
|
||||
self._pred = pred
|
||||
|
||||
def __len__(self):
|
||||
return len(self._succ.keys() | self._pred.keys())
|
||||
|
||||
def __iter__(self):
|
||||
return iter(set(self._succ.keys()) | set(self._pred.keys()))
|
||||
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
return self._succ[key]
|
||||
except KeyError:
|
||||
return self._pred[key]
|
||||
|
||||
def copy(self):
|
||||
result = {nbr: dd.copy() for nbr, dd in self._succ.items()}
|
||||
for nbr, dd in self._pred.items():
|
||||
if nbr in result:
|
||||
result[nbr].update(dd)
|
||||
else:
|
||||
result[nbr] = dd.copy()
|
||||
return result
|
||||
|
||||
def __str__(self):
|
||||
return str({nbr: self[nbr] for nbr in self})
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.__class__.__name__}({self._succ!r}, {self._pred!r})"
|
||||
|
||||
|
||||
class UnionAdjacency(Mapping):
|
||||
"""A read-only union of dict Adjacencies as a Map of Maps of Maps.
|
||||
|
||||
The two input dict-of-dict-of-dicts represent the union of
|
||||
`G.succ` and `G.pred`. Return values are UnionAtlas
|
||||
The inner level of dict is read-write. But the
|
||||
middle and outer levels are read-only.
|
||||
|
||||
succ : a dict-of-dict-of-dict {node: nbrdict}
|
||||
pred : a dict-of-dict-of-dict {node: nbrdict}
|
||||
The keys for the two dicts should be the same
|
||||
|
||||
See Also
|
||||
========
|
||||
UnionAtlas: View into dict-of-dict
|
||||
UnionMultiAdjacency: View into dict-of-dict-of-dict-of-dict
|
||||
"""
|
||||
|
||||
__slots__ = ("_succ", "_pred")
|
||||
|
||||
def __getstate__(self):
|
||||
return {"_succ": self._succ, "_pred": self._pred}
|
||||
|
||||
def __setstate__(self, state):
|
||||
self._succ = state["_succ"]
|
||||
self._pred = state["_pred"]
|
||||
|
||||
def __init__(self, succ, pred):
|
||||
# keys must be the same for two input dicts
|
||||
assert len(set(succ.keys()) ^ set(pred.keys())) == 0
|
||||
self._succ = succ
|
||||
self._pred = pred
|
||||
|
||||
def __len__(self):
|
||||
return len(self._succ) # length of each dict should be the same
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._succ)
|
||||
|
||||
def __getitem__(self, nbr):
|
||||
return UnionAtlas(self._succ[nbr], self._pred[nbr])
|
||||
|
||||
def copy(self):
|
||||
return {n: self[n].copy() for n in self._succ}
|
||||
|
||||
def __str__(self):
|
||||
return str({nbr: self[nbr] for nbr in self})
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.__class__.__name__}({self._succ!r}, {self._pred!r})"
|
||||
|
||||
|
||||
class UnionMultiInner(UnionAtlas):
|
||||
"""A read-only union of two inner dicts of MultiAdjacencies.
|
||||
|
||||
The two input dict-of-dict-of-dicts represent the union of
|
||||
`G.succ[node]` and `G.pred[node]` for MultiDiGraphs.
|
||||
Return values are UnionAtlas.
|
||||
The inner level of dict is read-write. But the outer levels are read-only.
|
||||
|
||||
See Also
|
||||
========
|
||||
UnionAtlas: View into dict-of-dict
|
||||
UnionAdjacency: View into dict-of-dict-of-dict
|
||||
UnionMultiAdjacency: View into dict-of-dict-of-dict-of-dict
|
||||
"""
|
||||
|
||||
__slots__ = () # Still uses UnionAtlas slots names _succ, _pred
|
||||
|
||||
def __getitem__(self, node):
|
||||
in_succ = node in self._succ
|
||||
in_pred = node in self._pred
|
||||
if in_succ:
|
||||
if in_pred:
|
||||
return UnionAtlas(self._succ[node], self._pred[node])
|
||||
return UnionAtlas(self._succ[node], {})
|
||||
return UnionAtlas({}, self._pred[node])
|
||||
|
||||
def copy(self):
|
||||
nodes = set(self._succ.keys()) | set(self._pred.keys())
|
||||
return {n: self[n].copy() for n in nodes}
|
||||
|
||||
|
||||
class UnionMultiAdjacency(UnionAdjacency):
|
||||
"""A read-only union of two dict MultiAdjacencies.
|
||||
|
||||
The two input dict-of-dict-of-dict-of-dicts represent the union of
|
||||
`G.succ` and `G.pred` for MultiDiGraphs. Return values are UnionAdjacency.
|
||||
The inner level of dict is read-write. But the outer levels are read-only.
|
||||
|
||||
See Also
|
||||
========
|
||||
UnionAtlas: View into dict-of-dict
|
||||
UnionMultiInner: View into dict-of-dict-of-dict
|
||||
"""
|
||||
|
||||
__slots__ = () # Still uses UnionAdjacency slots names _succ, _pred
|
||||
|
||||
def __getitem__(self, node):
|
||||
return UnionMultiInner(self._succ[node], self._pred[node])
|
||||
|
||||
|
||||
class FilterAtlas(Mapping): # nodedict, nbrdict, keydict
|
||||
def __init__(self, d, NODE_OK):
|
||||
self._atlas = d
|
||||
self.NODE_OK = NODE_OK
|
||||
|
||||
def __len__(self):
|
||||
return sum(1 for n in self)
|
||||
|
||||
def __iter__(self):
|
||||
try: # check that NODE_OK has attr 'nodes'
|
||||
node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas)
|
||||
except AttributeError:
|
||||
node_ok_shorter = False
|
||||
if node_ok_shorter:
|
||||
return (n for n in self.NODE_OK.nodes if n in self._atlas)
|
||||
return (n for n in self._atlas if self.NODE_OK(n))
|
||||
|
||||
def __getitem__(self, key):
|
||||
if key in self._atlas and self.NODE_OK(key):
|
||||
return self._atlas[key]
|
||||
raise KeyError(f"Key {key} not found")
|
||||
|
||||
def __str__(self):
|
||||
return str({nbr: self[nbr] for nbr in self})
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.__class__.__name__}({self._atlas!r}, {self.NODE_OK!r})"
|
||||
|
||||
|
||||
class FilterAdjacency(Mapping): # edgedict
|
||||
def __init__(self, d, NODE_OK, EDGE_OK):
|
||||
self._atlas = d
|
||||
self.NODE_OK = NODE_OK
|
||||
self.EDGE_OK = EDGE_OK
|
||||
|
||||
def __len__(self):
|
||||
return sum(1 for n in self)
|
||||
|
||||
def __iter__(self):
|
||||
try: # check that NODE_OK has attr 'nodes'
|
||||
node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas)
|
||||
except AttributeError:
|
||||
node_ok_shorter = False
|
||||
if node_ok_shorter:
|
||||
return (n for n in self.NODE_OK.nodes if n in self._atlas)
|
||||
return (n for n in self._atlas if self.NODE_OK(n))
|
||||
|
||||
def __getitem__(self, node):
|
||||
if node in self._atlas and self.NODE_OK(node):
|
||||
|
||||
def new_node_ok(nbr):
|
||||
return self.NODE_OK(nbr) and self.EDGE_OK(node, nbr)
|
||||
|
||||
return FilterAtlas(self._atlas[node], new_node_ok)
|
||||
raise KeyError(f"Key {node} not found")
|
||||
|
||||
def __str__(self):
|
||||
return str({nbr: self[nbr] for nbr in self})
|
||||
|
||||
def __repr__(self):
|
||||
name = self.__class__.__name__
|
||||
return f"{name}({self._atlas!r}, {self.NODE_OK!r}, {self.EDGE_OK!r})"
|
||||
|
||||
|
||||
class FilterMultiInner(FilterAdjacency): # muliedge_seconddict
|
||||
def __iter__(self):
|
||||
try: # check that NODE_OK has attr 'nodes'
|
||||
node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas)
|
||||
except AttributeError:
|
||||
node_ok_shorter = False
|
||||
if node_ok_shorter:
|
||||
my_nodes = (n for n in self.NODE_OK.nodes if n in self._atlas)
|
||||
else:
|
||||
my_nodes = (n for n in self._atlas if self.NODE_OK(n))
|
||||
for n in my_nodes:
|
||||
some_keys_ok = False
|
||||
for key in self._atlas[n]:
|
||||
if self.EDGE_OK(n, key):
|
||||
some_keys_ok = True
|
||||
break
|
||||
if some_keys_ok is True:
|
||||
yield n
|
||||
|
||||
def __getitem__(self, nbr):
|
||||
if nbr in self._atlas and self.NODE_OK(nbr):
|
||||
|
||||
def new_node_ok(key):
|
||||
return self.EDGE_OK(nbr, key)
|
||||
|
||||
return FilterAtlas(self._atlas[nbr], new_node_ok)
|
||||
raise KeyError(f"Key {nbr} not found")
|
||||
|
||||
|
||||
class FilterMultiAdjacency(FilterAdjacency): # multiedgedict
|
||||
def __getitem__(self, node):
|
||||
if node in self._atlas and self.NODE_OK(node):
|
||||
|
||||
def edge_ok(nbr, key):
|
||||
return self.NODE_OK(nbr) and self.EDGE_OK(node, nbr, key)
|
||||
|
||||
return FilterMultiInner(self._atlas[node], self.NODE_OK, edge_ok)
|
||||
raise KeyError(f"Key {node} not found")
|
||||
1323
.CondaPkg/env/Lib/site-packages/networkx/classes/digraph.py
vendored
Normal file
1323
.CondaPkg/env/Lib/site-packages/networkx/classes/digraph.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
75
.CondaPkg/env/Lib/site-packages/networkx/classes/filters.py
vendored
Normal file
75
.CondaPkg/env/Lib/site-packages/networkx/classes/filters.py
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
"""Filter factories to hide or show sets of nodes and edges.
|
||||
|
||||
These filters return the function used when creating `SubGraph`.
|
||||
"""
|
||||
__all__ = [
|
||||
"no_filter",
|
||||
"hide_nodes",
|
||||
"hide_edges",
|
||||
"hide_multiedges",
|
||||
"hide_diedges",
|
||||
"hide_multidiedges",
|
||||
"show_nodes",
|
||||
"show_edges",
|
||||
"show_multiedges",
|
||||
"show_diedges",
|
||||
"show_multidiedges",
|
||||
]
|
||||
|
||||
|
||||
def no_filter(*items):
|
||||
return True
|
||||
|
||||
|
||||
def hide_nodes(nodes):
|
||||
nodes = set(nodes)
|
||||
return lambda node: node not in nodes
|
||||
|
||||
|
||||
def hide_diedges(edges):
|
||||
edges = {(u, v) for u, v in edges}
|
||||
return lambda u, v: (u, v) not in edges
|
||||
|
||||
|
||||
def hide_edges(edges):
|
||||
alledges = set(edges) | {(v, u) for (u, v) in edges}
|
||||
return lambda u, v: (u, v) not in alledges
|
||||
|
||||
|
||||
def hide_multidiedges(edges):
|
||||
edges = {(u, v, k) for u, v, k in edges}
|
||||
return lambda u, v, k: (u, v, k) not in edges
|
||||
|
||||
|
||||
def hide_multiedges(edges):
|
||||
alledges = set(edges) | {(v, u, k) for (u, v, k) in edges}
|
||||
return lambda u, v, k: (u, v, k) not in alledges
|
||||
|
||||
|
||||
# write show_nodes as a class to make SubGraph pickleable
|
||||
class show_nodes:
|
||||
def __init__(self, nodes):
|
||||
self.nodes = set(nodes)
|
||||
|
||||
def __call__(self, node):
|
||||
return node in self.nodes
|
||||
|
||||
|
||||
def show_diedges(edges):
|
||||
edges = {(u, v) for u, v in edges}
|
||||
return lambda u, v: (u, v) in edges
|
||||
|
||||
|
||||
def show_edges(edges):
|
||||
alledges = set(edges) | {(v, u) for (u, v) in edges}
|
||||
return lambda u, v: (u, v) in alledges
|
||||
|
||||
|
||||
def show_multidiedges(edges):
|
||||
edges = {(u, v, k) for u, v, k in edges}
|
||||
return lambda u, v, k: (u, v, k) in edges
|
||||
|
||||
|
||||
def show_multiedges(edges):
|
||||
alledges = set(edges) | {(v, u, k) for (u, v, k) in edges}
|
||||
return lambda u, v, k: (u, v, k) in alledges
|
||||
1294
.CondaPkg/env/Lib/site-packages/networkx/classes/function.py
vendored
Normal file
1294
.CondaPkg/env/Lib/site-packages/networkx/classes/function.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2028
.CondaPkg/env/Lib/site-packages/networkx/classes/graph.py
vendored
Normal file
2028
.CondaPkg/env/Lib/site-packages/networkx/classes/graph.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
205
.CondaPkg/env/Lib/site-packages/networkx/classes/graphviews.py
vendored
Normal file
205
.CondaPkg/env/Lib/site-packages/networkx/classes/graphviews.py
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
"""View of Graphs as SubGraph, Reverse, Directed, Undirected.
|
||||
|
||||
In some algorithms it is convenient to temporarily morph
|
||||
a graph to exclude some nodes or edges. It should be better
|
||||
to do that via a view than to remove and then re-add.
|
||||
In other algorithms it is convenient to temporarily morph
|
||||
a graph to reverse directed edges, or treat a directed graph
|
||||
as undirected, etc. This module provides those graph views.
|
||||
|
||||
The resulting views are essentially read-only graphs that
|
||||
report data from the original graph object. We provide an
|
||||
attribute G._graph which points to the underlying graph object.
|
||||
|
||||
Note: Since graphviews look like graphs, one can end up with
|
||||
view-of-view-of-view chains. Be careful with chains because
|
||||
they become very slow with about 15 nested views.
|
||||
For the common simple case of node induced subgraphs created
|
||||
from the graph class, we short-cut the chain by returning a
|
||||
subgraph of the original graph directly rather than a subgraph
|
||||
of a subgraph. We are careful not to disrupt any edge filter in
|
||||
the middle subgraph. In general, determining how to short-cut
|
||||
the chain is tricky and much harder with restricted_views than
|
||||
with induced subgraphs.
|
||||
Often it is easiest to use .copy() to avoid chains.
|
||||
"""
|
||||
import networkx as nx
|
||||
from networkx.classes.coreviews import (
|
||||
FilterAdjacency,
|
||||
FilterAtlas,
|
||||
FilterMultiAdjacency,
|
||||
UnionAdjacency,
|
||||
UnionMultiAdjacency,
|
||||
)
|
||||
from networkx.classes.filters import no_filter
|
||||
from networkx.exception import NetworkXError
|
||||
from networkx.utils import not_implemented_for
|
||||
|
||||
__all__ = ["generic_graph_view", "subgraph_view", "reverse_view"]
|
||||
|
||||
|
||||
def generic_graph_view(G, create_using=None):
|
||||
if create_using is None:
|
||||
newG = G.__class__()
|
||||
else:
|
||||
newG = nx.empty_graph(0, create_using)
|
||||
if G.is_multigraph() != newG.is_multigraph():
|
||||
raise NetworkXError("Multigraph for G must agree with create_using")
|
||||
newG = nx.freeze(newG)
|
||||
|
||||
# create view by assigning attributes from G
|
||||
newG._graph = G
|
||||
newG.graph = G.graph
|
||||
|
||||
newG._node = G._node
|
||||
if newG.is_directed():
|
||||
if G.is_directed():
|
||||
newG._succ = G._succ
|
||||
newG._pred = G._pred
|
||||
# newG._adj is synced with _succ
|
||||
else:
|
||||
newG._succ = G._adj
|
||||
newG._pred = G._adj
|
||||
# newG._adj is synced with _succ
|
||||
elif G.is_directed():
|
||||
if G.is_multigraph():
|
||||
newG._adj = UnionMultiAdjacency(G._succ, G._pred)
|
||||
else:
|
||||
newG._adj = UnionAdjacency(G._succ, G._pred)
|
||||
else:
|
||||
newG._adj = G._adj
|
||||
return newG
|
||||
|
||||
|
||||
def subgraph_view(G, filter_node=no_filter, filter_edge=no_filter):
|
||||
"""View of `G` applying a filter on nodes and edges.
|
||||
|
||||
`subgraph_view` provides a read-only view of the input graph that excludes
|
||||
nodes and edges based on the outcome of two filter functions `filter_node`
|
||||
and `filter_edge`.
|
||||
|
||||
The `filter_node` function takes one argument --- the node --- and returns
|
||||
`True` if the node should be included in the subgraph, and `False` if it
|
||||
should not be included.
|
||||
|
||||
The `filter_edge` function takes two (or three arguments if `G` is a
|
||||
multi-graph) --- the nodes describing an edge, plus the edge-key if
|
||||
parallel edges are possible --- and returns `True` if the edge should be
|
||||
included in the subgraph, and `False` if it should not be included.
|
||||
|
||||
Both node and edge filter functions are called on graph elements as they
|
||||
are queried, meaning there is no up-front cost to creating the view.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : networkx.Graph
|
||||
A directed/undirected graph/multigraph
|
||||
|
||||
filter_node : callable, optional
|
||||
A function taking a node as input, which returns `True` if the node
|
||||
should appear in the view.
|
||||
|
||||
filter_edge : callable, optional
|
||||
A function taking as input the two nodes describing an edge (plus the
|
||||
edge-key if `G` is a multi-graph), which returns `True` if the edge
|
||||
should appear in the view.
|
||||
|
||||
Returns
|
||||
-------
|
||||
graph : networkx.Graph
|
||||
A read-only graph view of the input graph.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> G = nx.path_graph(6)
|
||||
|
||||
Filter functions operate on the node, and return `True` if the node should
|
||||
appear in the view:
|
||||
|
||||
>>> def filter_node(n1):
|
||||
... return n1 != 5
|
||||
...
|
||||
>>> view = nx.subgraph_view(G, filter_node=filter_node)
|
||||
>>> view.nodes()
|
||||
NodeView((0, 1, 2, 3, 4))
|
||||
|
||||
We can use a closure pattern to filter graph elements based on additional
|
||||
data --- for example, filtering on edge data attached to the graph:
|
||||
|
||||
>>> G[3][4]["cross_me"] = False
|
||||
>>> def filter_edge(n1, n2):
|
||||
... return G[n1][n2].get("cross_me", True)
|
||||
...
|
||||
>>> view = nx.subgraph_view(G, filter_edge=filter_edge)
|
||||
>>> view.edges()
|
||||
EdgeView([(0, 1), (1, 2), (2, 3), (4, 5)])
|
||||
|
||||
>>> view = nx.subgraph_view(G, filter_node=filter_node, filter_edge=filter_edge,)
|
||||
>>> view.nodes()
|
||||
NodeView((0, 1, 2, 3, 4))
|
||||
>>> view.edges()
|
||||
EdgeView([(0, 1), (1, 2), (2, 3)])
|
||||
"""
|
||||
newG = nx.freeze(G.__class__())
|
||||
newG._NODE_OK = filter_node
|
||||
newG._EDGE_OK = filter_edge
|
||||
|
||||
# create view by assigning attributes from G
|
||||
newG._graph = G
|
||||
newG.graph = G.graph
|
||||
|
||||
newG._node = FilterAtlas(G._node, filter_node)
|
||||
if G.is_multigraph():
|
||||
Adj = FilterMultiAdjacency
|
||||
|
||||
def reverse_edge(u, v, k=None):
|
||||
return filter_edge(v, u, k)
|
||||
|
||||
else:
|
||||
Adj = FilterAdjacency
|
||||
|
||||
def reverse_edge(u, v, k=None):
|
||||
return filter_edge(v, u)
|
||||
|
||||
if G.is_directed():
|
||||
newG._succ = Adj(G._succ, filter_node, filter_edge)
|
||||
newG._pred = Adj(G._pred, filter_node, reverse_edge)
|
||||
# newG._adj is synced with _succ
|
||||
else:
|
||||
newG._adj = Adj(G._adj, filter_node, filter_edge)
|
||||
return newG
|
||||
|
||||
|
||||
@not_implemented_for("undirected")
|
||||
def reverse_view(G):
|
||||
"""View of `G` with edge directions reversed
|
||||
|
||||
`reverse_view` returns a read-only view of the input graph where
|
||||
edge directions are reversed.
|
||||
|
||||
Identical to digraph.reverse(copy=False)
|
||||
|
||||
Parameters
|
||||
----------
|
||||
G : networkx.DiGraph
|
||||
|
||||
Returns
|
||||
-------
|
||||
graph : networkx.DiGraph
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> G = nx.DiGraph()
|
||||
>>> G.add_edge(1, 2)
|
||||
>>> G.add_edge(2, 3)
|
||||
>>> G.edges()
|
||||
OutEdgeView([(1, 2), (2, 3)])
|
||||
|
||||
>>> view = nx.reverse_view(G)
|
||||
>>> view.edges()
|
||||
OutEdgeView([(2, 1), (3, 2)])
|
||||
"""
|
||||
newG = generic_graph_view(G)
|
||||
newG._succ, newG._pred = G._pred, G._succ
|
||||
# newG._adj is synced with _succ
|
||||
return newG
|
||||
963
.CondaPkg/env/Lib/site-packages/networkx/classes/multidigraph.py
vendored
Normal file
963
.CondaPkg/env/Lib/site-packages/networkx/classes/multidigraph.py
vendored
Normal file
@@ -0,0 +1,963 @@
|
||||
"""Base class for MultiDiGraph."""
|
||||
from copy import deepcopy
|
||||
from functools import cached_property
|
||||
|
||||
import networkx as nx
|
||||
from networkx import convert
|
||||
from networkx.classes.coreviews import MultiAdjacencyView
|
||||
from networkx.classes.digraph import DiGraph
|
||||
from networkx.classes.multigraph import MultiGraph
|
||||
from networkx.classes.reportviews import (
|
||||
DiMultiDegreeView,
|
||||
InMultiDegreeView,
|
||||
InMultiEdgeView,
|
||||
OutMultiDegreeView,
|
||||
OutMultiEdgeView,
|
||||
)
|
||||
from networkx.exception import NetworkXError
|
||||
|
||||
__all__ = ["MultiDiGraph"]
|
||||
|
||||
|
||||
class MultiDiGraph(MultiGraph, DiGraph):
|
||||
"""A directed graph class that can store multiedges.
|
||||
|
||||
Multiedges are multiple edges between two nodes. Each edge
|
||||
can hold optional data or attributes.
|
||||
|
||||
A MultiDiGraph holds directed edges. Self loops are allowed.
|
||||
|
||||
Nodes can be arbitrary (hashable) Python objects with optional
|
||||
key/value attributes. By convention `None` is not used as a node.
|
||||
|
||||
Edges are represented as links between nodes with optional
|
||||
key/value attributes.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
incoming_graph_data : input graph (optional, default: None)
|
||||
Data to initialize graph. If None (default) an empty
|
||||
graph is created. The data can be any format that is supported
|
||||
by the to_networkx_graph() function, currently including edge list,
|
||||
dict of dicts, dict of lists, NetworkX graph, 2D NumPy array, SciPy
|
||||
sparse matrix, or PyGraphviz graph.
|
||||
|
||||
multigraph_input : bool or None (default None)
|
||||
Note: Only used when `incoming_graph_data` is a dict.
|
||||
If True, `incoming_graph_data` is assumed to be a
|
||||
dict-of-dict-of-dict-of-dict structure keyed by
|
||||
node to neighbor to edge keys to edge data for multi-edges.
|
||||
A NetworkXError is raised if this is not the case.
|
||||
If False, :func:`to_networkx_graph` is used to try to determine
|
||||
the dict's graph data structure as either a dict-of-dict-of-dict
|
||||
keyed by node to neighbor to edge data, or a dict-of-iterable
|
||||
keyed by node to neighbors.
|
||||
If None, the treatment for True is tried, but if it fails,
|
||||
the treatment for False is tried.
|
||||
|
||||
attr : keyword arguments, optional (default= no attributes)
|
||||
Attributes to add to graph as key=value pairs.
|
||||
|
||||
See Also
|
||||
--------
|
||||
Graph
|
||||
DiGraph
|
||||
MultiGraph
|
||||
|
||||
Examples
|
||||
--------
|
||||
Create an empty graph structure (a "null graph") with no nodes and
|
||||
no edges.
|
||||
|
||||
>>> G = nx.MultiDiGraph()
|
||||
|
||||
G can be grown in several ways.
|
||||
|
||||
**Nodes:**
|
||||
|
||||
Add one node at a time:
|
||||
|
||||
>>> G.add_node(1)
|
||||
|
||||
Add the nodes from any container (a list, dict, set or
|
||||
even the lines from a file or the nodes from another graph).
|
||||
|
||||
>>> G.add_nodes_from([2, 3])
|
||||
>>> G.add_nodes_from(range(100, 110))
|
||||
>>> H = nx.path_graph(10)
|
||||
>>> G.add_nodes_from(H)
|
||||
|
||||
In addition to strings and integers any hashable Python object
|
||||
(except None) can represent a node, e.g. a customized node object,
|
||||
or even another Graph.
|
||||
|
||||
>>> G.add_node(H)
|
||||
|
||||
**Edges:**
|
||||
|
||||
G can also be grown by adding edges.
|
||||
|
||||
Add one edge,
|
||||
|
||||
>>> key = G.add_edge(1, 2)
|
||||
|
||||
a list of edges,
|
||||
|
||||
>>> keys = G.add_edges_from([(1, 2), (1, 3)])
|
||||
|
||||
or a collection of edges,
|
||||
|
||||
>>> keys = G.add_edges_from(H.edges)
|
||||
|
||||
If some edges connect nodes not yet in the graph, the nodes
|
||||
are added automatically. If an edge already exists, an additional
|
||||
edge is created and stored using a key to identify the edge.
|
||||
By default the key is the lowest unused integer.
|
||||
|
||||
>>> keys = G.add_edges_from([(4, 5, dict(route=282)), (4, 5, dict(route=37))])
|
||||
>>> G[4]
|
||||
AdjacencyView({5: {0: {}, 1: {'route': 282}, 2: {'route': 37}}})
|
||||
|
||||
**Attributes:**
|
||||
|
||||
Each graph, node, and edge can hold key/value attribute pairs
|
||||
in an associated attribute dictionary (the keys must be hashable).
|
||||
By default these are empty, but can be added or changed using
|
||||
add_edge, add_node or direct manipulation of the attribute
|
||||
dictionaries named graph, node and edge respectively.
|
||||
|
||||
>>> G = nx.MultiDiGraph(day="Friday")
|
||||
>>> G.graph
|
||||
{'day': 'Friday'}
|
||||
|
||||
Add node attributes using add_node(), add_nodes_from() or G.nodes
|
||||
|
||||
>>> G.add_node(1, time="5pm")
|
||||
>>> G.add_nodes_from([3], time="2pm")
|
||||
>>> G.nodes[1]
|
||||
{'time': '5pm'}
|
||||
>>> G.nodes[1]["room"] = 714
|
||||
>>> del G.nodes[1]["room"] # remove attribute
|
||||
>>> list(G.nodes(data=True))
|
||||
[(1, {'time': '5pm'}), (3, {'time': '2pm'})]
|
||||
|
||||
Add edge attributes using add_edge(), add_edges_from(), subscript
|
||||
notation, or G.edges.
|
||||
|
||||
>>> key = G.add_edge(1, 2, weight=4.7)
|
||||
>>> keys = G.add_edges_from([(3, 4), (4, 5)], color="red")
|
||||
>>> keys = G.add_edges_from([(1, 2, {"color": "blue"}), (2, 3, {"weight": 8})])
|
||||
>>> G[1][2][0]["weight"] = 4.7
|
||||
>>> G.edges[1, 2, 0]["weight"] = 4
|
||||
|
||||
Warning: we protect the graph data structure by making `G.edges[1,
|
||||
2, 0]` a read-only dict-like structure. However, you can assign to
|
||||
attributes in e.g. `G.edges[1, 2, 0]`. Thus, use 2 sets of brackets
|
||||
to add/change data attributes: `G.edges[1, 2, 0]['weight'] = 4`
|
||||
(for multigraphs the edge key is required: `MG.edges[u, v,
|
||||
key][name] = value`).
|
||||
|
||||
**Shortcuts:**
|
||||
|
||||
Many common graph features allow python syntax to speed reporting.
|
||||
|
||||
>>> 1 in G # check if node in graph
|
||||
True
|
||||
>>> [n for n in G if n < 3] # iterate through nodes
|
||||
[1, 2]
|
||||
>>> len(G) # number of nodes in graph
|
||||
5
|
||||
>>> G[1] # adjacency dict-like view mapping neighbor -> edge key -> edge attributes
|
||||
AdjacencyView({2: {0: {'weight': 4}, 1: {'color': 'blue'}}})
|
||||
|
||||
Often the best way to traverse all edges of a graph is via the neighbors.
|
||||
The neighbors are available as an adjacency-view `G.adj` object or via
|
||||
the method `G.adjacency()`.
|
||||
|
||||
>>> for n, nbrsdict in G.adjacency():
|
||||
... for nbr, keydict in nbrsdict.items():
|
||||
... for key, eattr in keydict.items():
|
||||
... if "weight" in eattr:
|
||||
... # Do something useful with the edges
|
||||
... pass
|
||||
|
||||
But the edges() method is often more convenient:
|
||||
|
||||
>>> for u, v, keys, weight in G.edges(data="weight", keys=True):
|
||||
... if weight is not None:
|
||||
... # Do something useful with the edges
|
||||
... pass
|
||||
|
||||
**Reporting:**
|
||||
|
||||
Simple graph information is obtained using methods and object-attributes.
|
||||
Reporting usually provides views instead of containers to reduce memory
|
||||
usage. The views update as the graph is updated similarly to dict-views.
|
||||
The objects `nodes`, `edges` and `adj` provide access to data attributes
|
||||
via lookup (e.g. `nodes[n]`, `edges[u, v, k]`, `adj[u][v]`) and iteration
|
||||
(e.g. `nodes.items()`, `nodes.data('color')`,
|
||||
`nodes.data('color', default='blue')` and similarly for `edges`)
|
||||
Views exist for `nodes`, `edges`, `neighbors()`/`adj` and `degree`.
|
||||
|
||||
For details on these and other miscellaneous methods, see below.
|
||||
|
||||
**Subclasses (Advanced):**
|
||||
|
||||
The MultiDiGraph class uses a dict-of-dict-of-dict-of-dict structure.
|
||||
The outer dict (node_dict) holds adjacency information keyed by node.
|
||||
The next dict (adjlist_dict) represents the adjacency information
|
||||
and holds edge_key dicts keyed by neighbor. The edge_key dict holds
|
||||
each edge_attr dict keyed by edge key. The inner dict
|
||||
(edge_attr_dict) represents the edge data and holds edge attribute
|
||||
values keyed by attribute names.
|
||||
|
||||
Each of these four dicts in the dict-of-dict-of-dict-of-dict
|
||||
structure can be replaced by a user defined dict-like object.
|
||||
In general, the dict-like features should be maintained but
|
||||
extra features can be added. To replace one of the dicts create
|
||||
a new graph class by changing the class(!) variable holding the
|
||||
factory for that dict-like structure. The variable names are
|
||||
node_dict_factory, node_attr_dict_factory, adjlist_inner_dict_factory,
|
||||
adjlist_outer_dict_factory, edge_key_dict_factory, edge_attr_dict_factory
|
||||
and graph_attr_dict_factory.
|
||||
|
||||
node_dict_factory : function, (default: dict)
|
||||
Factory function to be used to create the dict containing node
|
||||
attributes, keyed by node id.
|
||||
It should require no arguments and return a dict-like object
|
||||
|
||||
node_attr_dict_factory: function, (default: dict)
|
||||
Factory function to be used to create the node attribute
|
||||
dict which holds attribute values keyed by attribute name.
|
||||
It should require no arguments and return a dict-like object
|
||||
|
||||
adjlist_outer_dict_factory : function, (default: dict)
|
||||
Factory function to be used to create the outer-most dict
|
||||
in the data structure that holds adjacency info keyed by node.
|
||||
It should require no arguments and return a dict-like object.
|
||||
|
||||
adjlist_inner_dict_factory : function, (default: dict)
|
||||
Factory function to be used to create the adjacency list
|
||||
dict which holds multiedge key dicts keyed by neighbor.
|
||||
It should require no arguments and return a dict-like object.
|
||||
|
||||
edge_key_dict_factory : function, (default: dict)
|
||||
Factory function to be used to create the edge key dict
|
||||
which holds edge data keyed by edge key.
|
||||
It should require no arguments and return a dict-like object.
|
||||
|
||||
edge_attr_dict_factory : function, (default: dict)
|
||||
Factory function to be used to create the edge attribute
|
||||
dict which holds attribute values keyed by attribute name.
|
||||
It should require no arguments and return a dict-like object.
|
||||
|
||||
graph_attr_dict_factory : function, (default: dict)
|
||||
Factory function to be used to create the graph attribute
|
||||
dict which holds attribute values keyed by attribute name.
|
||||
It should require no arguments and return a dict-like object.
|
||||
|
||||
Typically, if your extension doesn't impact the data structure all
|
||||
methods will inherited without issue except: `to_directed/to_undirected`.
|
||||
By default these methods create a DiGraph/Graph class and you probably
|
||||
want them to create your extension of a DiGraph/Graph. To facilitate
|
||||
this we define two class variables that you can set in your subclass.
|
||||
|
||||
to_directed_class : callable, (default: DiGraph or MultiDiGraph)
|
||||
Class to create a new graph structure in the `to_directed` method.
|
||||
If `None`, a NetworkX class (DiGraph or MultiDiGraph) is used.
|
||||
|
||||
to_undirected_class : callable, (default: Graph or MultiGraph)
|
||||
Class to create a new graph structure in the `to_undirected` method.
|
||||
If `None`, a NetworkX class (Graph or MultiGraph) is used.
|
||||
|
||||
**Subclassing Example**
|
||||
|
||||
Create a low memory graph class that effectively disallows edge
|
||||
attributes by using a single attribute dict for all edges.
|
||||
This reduces the memory used, but you lose edge attributes.
|
||||
|
||||
>>> class ThinGraph(nx.Graph):
|
||||
... all_edge_dict = {"weight": 1}
|
||||
...
|
||||
... def single_edge_dict(self):
|
||||
... return self.all_edge_dict
|
||||
...
|
||||
... edge_attr_dict_factory = single_edge_dict
|
||||
>>> G = ThinGraph()
|
||||
>>> G.add_edge(2, 1)
|
||||
>>> G[2][1]
|
||||
{'weight': 1}
|
||||
>>> G.add_edge(2, 2)
|
||||
>>> G[2][1] is G[2][2]
|
||||
True
|
||||
"""
|
||||
|
||||
# node_dict_factory = dict # already assigned in Graph
|
||||
# adjlist_outer_dict_factory = dict
|
||||
# adjlist_inner_dict_factory = dict
|
||||
edge_key_dict_factory = dict
|
||||
# edge_attr_dict_factory = dict
|
||||
|
||||
def __init__(self, incoming_graph_data=None, multigraph_input=None, **attr):
|
||||
"""Initialize a graph with edges, name, or graph attributes.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
incoming_graph_data : input graph
|
||||
Data to initialize graph. If incoming_graph_data=None (default)
|
||||
an empty graph is created. The data can be an edge list, or any
|
||||
NetworkX graph object. If the corresponding optional Python
|
||||
packages are installed the data can also be a 2D NumPy array, a
|
||||
SciPy sparse array, or a PyGraphviz graph.
|
||||
|
||||
multigraph_input : bool or None (default None)
|
||||
Note: Only used when `incoming_graph_data` is a dict.
|
||||
If True, `incoming_graph_data` is assumed to be a
|
||||
dict-of-dict-of-dict-of-dict structure keyed by
|
||||
node to neighbor to edge keys to edge data for multi-edges.
|
||||
A NetworkXError is raised if this is not the case.
|
||||
If False, :func:`to_networkx_graph` is used to try to determine
|
||||
the dict's graph data structure as either a dict-of-dict-of-dict
|
||||
keyed by node to neighbor to edge data, or a dict-of-iterable
|
||||
keyed by node to neighbors.
|
||||
If None, the treatment for True is tried, but if it fails,
|
||||
the treatment for False is tried.
|
||||
|
||||
attr : keyword arguments, optional (default= no attributes)
|
||||
Attributes to add to graph as key=value pairs.
|
||||
|
||||
See Also
|
||||
--------
|
||||
convert
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc
|
||||
>>> G = nx.Graph(name="my graph")
|
||||
>>> e = [(1, 2), (2, 3), (3, 4)] # list of edges
|
||||
>>> G = nx.Graph(e)
|
||||
|
||||
Arbitrary graph attribute pairs (key=value) may be assigned
|
||||
|
||||
>>> G = nx.Graph(e, day="Friday")
|
||||
>>> G.graph
|
||||
{'day': 'Friday'}
|
||||
|
||||
"""
|
||||
# multigraph_input can be None/True/False. So check "is not False"
|
||||
if isinstance(incoming_graph_data, dict) and multigraph_input is not False:
|
||||
DiGraph.__init__(self)
|
||||
try:
|
||||
convert.from_dict_of_dicts(
|
||||
incoming_graph_data, create_using=self, multigraph_input=True
|
||||
)
|
||||
self.graph.update(attr)
|
||||
except Exception as err:
|
||||
if multigraph_input is True:
|
||||
raise nx.NetworkXError(
|
||||
f"converting multigraph_input raised:\n{type(err)}: {err}"
|
||||
)
|
||||
DiGraph.__init__(self, incoming_graph_data, **attr)
|
||||
else:
|
||||
DiGraph.__init__(self, incoming_graph_data, **attr)
|
||||
|
||||
@cached_property
|
||||
def adj(self):
|
||||
"""Graph adjacency object holding the neighbors of each node.
|
||||
|
||||
This object is a read-only dict-like structure with node keys
|
||||
and neighbor-dict values. The neighbor-dict is keyed by neighbor
|
||||
to the edgekey-dict. So `G.adj[3][2][0]['color'] = 'blue'` sets
|
||||
the color of the edge `(3, 2, 0)` to `"blue"`.
|
||||
|
||||
Iterating over G.adj behaves like a dict. Useful idioms include
|
||||
`for nbr, datadict in G.adj[n].items():`.
|
||||
|
||||
The neighbor information is also provided by subscripting the graph.
|
||||
So `for nbr, foovalue in G[node].data('foo', default=1):` works.
|
||||
|
||||
For directed graphs, `G.adj` holds outgoing (successor) info.
|
||||
"""
|
||||
return MultiAdjacencyView(self._succ)
|
||||
|
||||
@cached_property
|
||||
def succ(self):
|
||||
"""Graph adjacency object holding the successors of each node.
|
||||
|
||||
This object is a read-only dict-like structure with node keys
|
||||
and neighbor-dict values. The neighbor-dict is keyed by neighbor
|
||||
to the edgekey-dict. So `G.adj[3][2][0]['color'] = 'blue'` sets
|
||||
the color of the edge `(3, 2, 0)` to `"blue"`.
|
||||
|
||||
Iterating over G.adj behaves like a dict. Useful idioms include
|
||||
`for nbr, datadict in G.adj[n].items():`.
|
||||
|
||||
The neighbor information is also provided by subscripting the graph.
|
||||
So `for nbr, foovalue in G[node].data('foo', default=1):` works.
|
||||
|
||||
For directed graphs, `G.succ` is identical to `G.adj`.
|
||||
"""
|
||||
return MultiAdjacencyView(self._succ)
|
||||
|
||||
@cached_property
|
||||
def pred(self):
|
||||
"""Graph adjacency object holding the predecessors of each node.
|
||||
|
||||
This object is a read-only dict-like structure with node keys
|
||||
and neighbor-dict values. The neighbor-dict is keyed by neighbor
|
||||
to the edgekey-dict. So `G.adj[3][2][0]['color'] = 'blue'` sets
|
||||
the color of the edge `(3, 2, 0)` to `"blue"`.
|
||||
|
||||
Iterating over G.adj behaves like a dict. Useful idioms include
|
||||
`for nbr, datadict in G.adj[n].items():`.
|
||||
"""
|
||||
return MultiAdjacencyView(self._pred)
|
||||
|
||||
def add_edge(self, u_for_edge, v_for_edge, key=None, **attr):
|
||||
"""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_for_edge, v_for_edge : nodes
|
||||
Nodes can be, for example, strings or numbers.
|
||||
Nodes must be hashable (and not None) Python objects.
|
||||
key : hashable identifier, optional (default=lowest unused integer)
|
||||
Used to distinguish multiedges between a pair of nodes.
|
||||
attr : keyword arguments, optional
|
||||
Edge data (or labels or objects) can be assigned using
|
||||
keyword arguments.
|
||||
|
||||
Returns
|
||||
-------
|
||||
The edge key assigned to the edge.
|
||||
|
||||
See Also
|
||||
--------
|
||||
add_edges_from : add a collection of edges
|
||||
|
||||
Notes
|
||||
-----
|
||||
To replace/update edge data, use the optional key argument
|
||||
to identify a unique edge. Otherwise a new edge will be created.
|
||||
|
||||
NetworkX algorithms designed for weighted graphs cannot use
|
||||
multigraphs directly because it is not clear how to handle
|
||||
multiedge weights. Convert to Graph using edge attribute
|
||||
'weight' to enable weighted graph algorithms.
|
||||
|
||||
Default keys are generated using the method `new_edge_key()`.
|
||||
This method can be overridden by subclassing the base class and
|
||||
providing a custom `new_edge_key()` method.
|
||||
|
||||
Examples
|
||||
--------
|
||||
The following all add the edge e=(1, 2) to graph G:
|
||||
|
||||
>>> G = nx.MultiDiGraph()
|
||||
>>> e = (1, 2)
|
||||
>>> key = G.add_edge(1, 2) # explicit two-node form
|
||||
>>> G.add_edge(*e) # single edge as tuple of two nodes
|
||||
1
|
||||
>>> G.add_edges_from([(1, 2)]) # add edges from iterable container
|
||||
[2]
|
||||
|
||||
Associate data to edges using keywords:
|
||||
|
||||
>>> key = G.add_edge(1, 2, weight=3)
|
||||
>>> key = G.add_edge(1, 2, key=0, weight=4) # update data for key=0
|
||||
>>> key = G.add_edge(1, 3, weight=7, capacity=15, length=342.7)
|
||||
|
||||
For non-string attribute keys, use subscript notation.
|
||||
|
||||
>>> ekey = G.add_edge(1, 2)
|
||||
>>> G[1][2][0].update({0: 5})
|
||||
>>> G.edges[1, 2, 0].update({0: 5})
|
||||
"""
|
||||
u, v = u_for_edge, v_for_edge
|
||||
# add nodes
|
||||
if u not in self._succ:
|
||||
if u is None:
|
||||
raise ValueError("None cannot be a node")
|
||||
self._succ[u] = self.adjlist_inner_dict_factory()
|
||||
self._pred[u] = self.adjlist_inner_dict_factory()
|
||||
self._node[u] = self.node_attr_dict_factory()
|
||||
if v not in self._succ:
|
||||
if v is None:
|
||||
raise ValueError("None cannot be a node")
|
||||
self._succ[v] = self.adjlist_inner_dict_factory()
|
||||
self._pred[v] = self.adjlist_inner_dict_factory()
|
||||
self._node[v] = self.node_attr_dict_factory()
|
||||
if key is None:
|
||||
key = self.new_edge_key(u, v)
|
||||
if v in self._succ[u]:
|
||||
keydict = self._adj[u][v]
|
||||
datadict = keydict.get(key, self.edge_attr_dict_factory())
|
||||
datadict.update(attr)
|
||||
keydict[key] = datadict
|
||||
else:
|
||||
# selfloops work this way without special treatment
|
||||
datadict = self.edge_attr_dict_factory()
|
||||
datadict.update(attr)
|
||||
keydict = self.edge_key_dict_factory()
|
||||
keydict[key] = datadict
|
||||
self._succ[u][v] = keydict
|
||||
self._pred[v][u] = keydict
|
||||
return key
|
||||
|
||||
def remove_edge(self, u, v, key=None):
|
||||
"""Remove an edge between u and v.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
u, v : nodes
|
||||
Remove an edge between nodes u and v.
|
||||
key : hashable identifier, optional (default=None)
|
||||
Used to distinguish multiple edges between a pair of nodes.
|
||||
If None, remove a single edge between u and v. If there are
|
||||
multiple edges, removes the last edge added in terms of
|
||||
insertion order.
|
||||
|
||||
Raises
|
||||
------
|
||||
NetworkXError
|
||||
If there is not an edge between u and v, or
|
||||
if there is no edge with the specified key.
|
||||
|
||||
See Also
|
||||
--------
|
||||
remove_edges_from : remove a collection of edges
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> G = nx.MultiDiGraph()
|
||||
>>> nx.add_path(G, [0, 1, 2, 3])
|
||||
>>> G.remove_edge(0, 1)
|
||||
>>> e = (1, 2)
|
||||
>>> G.remove_edge(*e) # unpacks e from an edge tuple
|
||||
|
||||
For multiple edges
|
||||
|
||||
>>> G = nx.MultiDiGraph()
|
||||
>>> G.add_edges_from([(1, 2), (1, 2), (1, 2)]) # key_list returned
|
||||
[0, 1, 2]
|
||||
|
||||
When ``key=None`` (the default), edges are removed in the opposite
|
||||
order that they were added:
|
||||
|
||||
>>> G.remove_edge(1, 2)
|
||||
>>> G.edges(keys=True)
|
||||
OutMultiEdgeView([(1, 2, 0), (1, 2, 1)])
|
||||
|
||||
For edges with keys
|
||||
|
||||
>>> G = nx.MultiDiGraph()
|
||||
>>> G.add_edge(1, 2, key="first")
|
||||
'first'
|
||||
>>> G.add_edge(1, 2, key="second")
|
||||
'second'
|
||||
>>> G.remove_edge(1, 2, key="first")
|
||||
>>> G.edges(keys=True)
|
||||
OutMultiEdgeView([(1, 2, 'second')])
|
||||
|
||||
"""
|
||||
try:
|
||||
d = self._adj[u][v]
|
||||
except KeyError as err:
|
||||
raise NetworkXError(f"The edge {u}-{v} is not in the graph.") from err
|
||||
# remove the edge with specified data
|
||||
if key is None:
|
||||
d.popitem()
|
||||
else:
|
||||
try:
|
||||
del d[key]
|
||||
except KeyError as err:
|
||||
msg = f"The edge {u}-{v} with key {key} is not in the graph."
|
||||
raise NetworkXError(msg) from err
|
||||
if len(d) == 0:
|
||||
# remove the key entries if last edge
|
||||
del self._succ[u][v]
|
||||
del self._pred[v][u]
|
||||
|
||||
@cached_property
|
||||
def edges(self):
|
||||
"""An OutMultiEdgeView of the Graph as G.edges or G.edges().
|
||||
|
||||
edges(self, nbunch=None, data=False, keys=False, default=None)
|
||||
|
||||
The OutMultiEdgeView provides set-like operations on the edge-tuples
|
||||
as well as edge attribute lookup. When called, it also provides
|
||||
an EdgeDataView object which allows control of access to edge
|
||||
attributes (but does not provide set-like operations).
|
||||
Hence, ``G.edges[u, v, k]['color']`` provides the value of the color
|
||||
attribute for the edge from ``u`` to ``v`` with key ``k`` while
|
||||
``for (u, v, k, c) in G.edges(data='color', default='red', keys=True):``
|
||||
iterates through all the edges yielding the color attribute with
|
||||
default `'red'` if no color attribute exists.
|
||||
|
||||
Edges are returned as tuples with optional data and keys
|
||||
in the order (node, neighbor, key, data). If ``keys=True`` is not
|
||||
provided, the tuples will just be (node, neighbor, data), but
|
||||
multiple tuples with the same node and neighbor will be
|
||||
generated when multiple edges between two nodes exist.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nbunch : single node, container, or all nodes (default= all nodes)
|
||||
The view will only report edges from these nodes.
|
||||
data : string or bool, optional (default=False)
|
||||
The edge attribute returned in 3-tuple (u, v, ddict[data]).
|
||||
If True, return edge attribute dict in 3-tuple (u, v, ddict).
|
||||
If False, return 2-tuple (u, v).
|
||||
keys : bool, optional (default=False)
|
||||
If True, return edge keys with each edge, creating (u, v, k,
|
||||
d) tuples when data is also requested (the default) and (u,
|
||||
v, k) tuples when data is not requested.
|
||||
default : value, optional (default=None)
|
||||
Value used for edges that don't have the requested attribute.
|
||||
Only relevant if data is not True or False.
|
||||
|
||||
Returns
|
||||
-------
|
||||
edges : OutMultiEdgeView
|
||||
A view of edge attributes, usually it iterates over (u, v)
|
||||
(u, v, k) or (u, v, k, d) tuples of edges, but can also be
|
||||
used for attribute lookup as ``edges[u, v, k]['foo']``.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Nodes in nbunch that are not in the graph will be (quietly) ignored.
|
||||
For directed graphs this returns the out-edges.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> G = nx.MultiDiGraph()
|
||||
>>> nx.add_path(G, [0, 1, 2])
|
||||
>>> key = G.add_edge(2, 3, weight=5)
|
||||
>>> key2 = G.add_edge(1, 2) # second edge between these nodes
|
||||
>>> [e for e in G.edges()]
|
||||
[(0, 1), (1, 2), (1, 2), (2, 3)]
|
||||
>>> list(G.edges(data=True)) # default data is {} (empty dict)
|
||||
[(0, 1, {}), (1, 2, {}), (1, 2, {}), (2, 3, {'weight': 5})]
|
||||
>>> list(G.edges(data="weight", default=1))
|
||||
[(0, 1, 1), (1, 2, 1), (1, 2, 1), (2, 3, 5)]
|
||||
>>> list(G.edges(keys=True)) # default keys are integers
|
||||
[(0, 1, 0), (1, 2, 0), (1, 2, 1), (2, 3, 0)]
|
||||
>>> list(G.edges(data=True, keys=True))
|
||||
[(0, 1, 0, {}), (1, 2, 0, {}), (1, 2, 1, {}), (2, 3, 0, {'weight': 5})]
|
||||
>>> list(G.edges(data="weight", default=1, keys=True))
|
||||
[(0, 1, 0, 1), (1, 2, 0, 1), (1, 2, 1, 1), (2, 3, 0, 5)]
|
||||
>>> list(G.edges([0, 2]))
|
||||
[(0, 1), (2, 3)]
|
||||
>>> list(G.edges(0))
|
||||
[(0, 1)]
|
||||
>>> list(G.edges(1))
|
||||
[(1, 2), (1, 2)]
|
||||
|
||||
See Also
|
||||
--------
|
||||
in_edges, out_edges
|
||||
"""
|
||||
return OutMultiEdgeView(self)
|
||||
|
||||
# alias out_edges to edges
|
||||
@cached_property
|
||||
def out_edges(self):
|
||||
return OutMultiEdgeView(self)
|
||||
|
||||
out_edges.__doc__ = edges.__doc__
|
||||
|
||||
@cached_property
|
||||
def in_edges(self):
|
||||
"""A view of the in edges of the graph as G.in_edges or G.in_edges().
|
||||
|
||||
in_edges(self, nbunch=None, data=False, keys=False, default=None)
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nbunch : single node, container, or all nodes (default= all nodes)
|
||||
The view will only report edges incident to these nodes.
|
||||
data : string or bool, optional (default=False)
|
||||
The edge attribute returned in 3-tuple (u, v, ddict[data]).
|
||||
If True, return edge attribute dict in 3-tuple (u, v, ddict).
|
||||
If False, return 2-tuple (u, v).
|
||||
keys : bool, optional (default=False)
|
||||
If True, return edge keys with each edge, creating 3-tuples
|
||||
(u, v, k) or with data, 4-tuples (u, v, k, d).
|
||||
default : value, optional (default=None)
|
||||
Value used for edges that don't have the requested attribute.
|
||||
Only relevant if data is not True or False.
|
||||
|
||||
Returns
|
||||
-------
|
||||
in_edges : InMultiEdgeView or InMultiEdgeDataView
|
||||
A view of edge attributes, usually it iterates over (u, v)
|
||||
or (u, v, k) or (u, v, k, d) tuples of edges, but can also be
|
||||
used for attribute lookup as `edges[u, v, k]['foo']`.
|
||||
|
||||
See Also
|
||||
--------
|
||||
edges
|
||||
"""
|
||||
return InMultiEdgeView(self)
|
||||
|
||||
@cached_property
|
||||
def degree(self):
|
||||
"""A DegreeView for the Graph as G.degree or G.degree().
|
||||
|
||||
The node degree is the number of edges adjacent to the node.
|
||||
The weighted node degree is the sum of the edge weights for
|
||||
edges incident to that node.
|
||||
|
||||
This object provides an iterator for (node, degree) as well as
|
||||
lookup for the degree for a single node.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nbunch : single node, container, or all nodes (default= all nodes)
|
||||
The view will only report edges incident to these nodes.
|
||||
|
||||
weight : string or None, optional (default=None)
|
||||
The name of an edge attribute that holds the numerical value used
|
||||
as a weight. If None, then each edge has weight 1.
|
||||
The degree is the sum of the edge weights adjacent to the node.
|
||||
|
||||
Returns
|
||||
-------
|
||||
DiMultiDegreeView or int
|
||||
If multiple nodes are requested (the default), returns a `DiMultiDegreeView`
|
||||
mapping nodes to their degree.
|
||||
If a single node is requested, returns the degree of the node as an integer.
|
||||
|
||||
See Also
|
||||
--------
|
||||
out_degree, in_degree
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> G = nx.MultiDiGraph()
|
||||
>>> nx.add_path(G, [0, 1, 2, 3])
|
||||
>>> G.degree(0) # node 0 with degree 1
|
||||
1
|
||||
>>> list(G.degree([0, 1, 2]))
|
||||
[(0, 1), (1, 2), (2, 2)]
|
||||
>>> G.add_edge(0, 1) # parallel edge
|
||||
1
|
||||
>>> list(G.degree([0, 1, 2])) # parallel edges are counted
|
||||
[(0, 2), (1, 3), (2, 2)]
|
||||
|
||||
"""
|
||||
return DiMultiDegreeView(self)
|
||||
|
||||
@cached_property
|
||||
def in_degree(self):
|
||||
"""A DegreeView for (node, in_degree) or in_degree for single node.
|
||||
|
||||
The node in-degree is the number of edges pointing in to the node.
|
||||
The weighted node degree is the sum of the edge weights for
|
||||
edges incident to that node.
|
||||
|
||||
This object provides an iterator for (node, degree) as well as
|
||||
lookup for the degree for a single node.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nbunch : single node, container, or all nodes (default= all nodes)
|
||||
The view will only report edges incident to these nodes.
|
||||
|
||||
weight : string or None, optional (default=None)
|
||||
The edge attribute that holds the numerical value used
|
||||
as a weight. If None, then each edge has weight 1.
|
||||
The degree is the sum of the edge weights adjacent to the node.
|
||||
|
||||
Returns
|
||||
-------
|
||||
If a single node is requested
|
||||
deg : int
|
||||
Degree of the node
|
||||
|
||||
OR if multiple nodes are requested
|
||||
nd_iter : iterator
|
||||
The iterator returns two-tuples of (node, in-degree).
|
||||
|
||||
See Also
|
||||
--------
|
||||
degree, out_degree
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> G = nx.MultiDiGraph()
|
||||
>>> nx.add_path(G, [0, 1, 2, 3])
|
||||
>>> G.in_degree(0) # node 0 with degree 0
|
||||
0
|
||||
>>> list(G.in_degree([0, 1, 2]))
|
||||
[(0, 0), (1, 1), (2, 1)]
|
||||
>>> G.add_edge(0, 1) # parallel edge
|
||||
1
|
||||
>>> list(G.in_degree([0, 1, 2])) # parallel edges counted
|
||||
[(0, 0), (1, 2), (2, 1)]
|
||||
|
||||
"""
|
||||
return InMultiDegreeView(self)
|
||||
|
||||
@cached_property
|
||||
def out_degree(self):
|
||||
"""Returns an iterator for (node, out-degree) or out-degree for single node.
|
||||
|
||||
out_degree(self, nbunch=None, weight=None)
|
||||
|
||||
The node out-degree is the number of edges pointing out of the node.
|
||||
This function returns the out-degree for a single node or an iterator
|
||||
for a bunch of nodes or if nothing is passed as argument.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
nbunch : single node, container, or all nodes (default= all nodes)
|
||||
The view will only report edges incident to these nodes.
|
||||
|
||||
weight : string or None, optional (default=None)
|
||||
The edge attribute that holds the numerical value used
|
||||
as a weight. If None, then each edge has weight 1.
|
||||
The degree is the sum of the edge weights.
|
||||
|
||||
Returns
|
||||
-------
|
||||
If a single node is requested
|
||||
deg : int
|
||||
Degree of the node
|
||||
|
||||
OR if multiple nodes are requested
|
||||
nd_iter : iterator
|
||||
The iterator returns two-tuples of (node, out-degree).
|
||||
|
||||
See Also
|
||||
--------
|
||||
degree, in_degree
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> G = nx.MultiDiGraph()
|
||||
>>> nx.add_path(G, [0, 1, 2, 3])
|
||||
>>> G.out_degree(0) # node 0 with degree 1
|
||||
1
|
||||
>>> list(G.out_degree([0, 1, 2]))
|
||||
[(0, 1), (1, 1), (2, 1)]
|
||||
>>> G.add_edge(0, 1) # parallel edge
|
||||
1
|
||||
>>> list(G.out_degree([0, 1, 2])) # counts parallel edges
|
||||
[(0, 2), (1, 1), (2, 1)]
|
||||
|
||||
"""
|
||||
return OutMultiDegreeView(self)
|
||||
|
||||
def is_multigraph(self):
|
||||
"""Returns True if graph is a multigraph, False otherwise."""
|
||||
return True
|
||||
|
||||
def is_directed(self):
|
||||
"""Returns True if graph is directed, False otherwise."""
|
||||
return True
|
||||
|
||||
def to_undirected(self, reciprocal=False, as_view=False):
|
||||
"""Returns an undirected representation of the digraph.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
reciprocal : bool (optional)
|
||||
If True only keep edges that appear in both directions
|
||||
in the original digraph.
|
||||
as_view : bool (optional, default=False)
|
||||
If True return an undirected view of the original directed graph.
|
||||
|
||||
Returns
|
||||
-------
|
||||
G : MultiGraph
|
||||
An undirected graph with the same name and nodes and
|
||||
with edge (u, v, data) if either (u, v, data) or (v, u, data)
|
||||
is in the digraph. If both edges exist in digraph and
|
||||
their edge data is different, only one edge is created
|
||||
with an arbitrary choice of which edge data to use.
|
||||
You must check and correct for this manually if desired.
|
||||
|
||||
See Also
|
||||
--------
|
||||
MultiGraph, copy, add_edge, add_edges_from
|
||||
|
||||
Notes
|
||||
-----
|
||||
This returns a "deepcopy" of the edge, node, and
|
||||
graph attributes which attempts to completely copy
|
||||
all of the data and references.
|
||||
|
||||
This is in contrast to the similar D=MultiDiGraph(G) which
|
||||
returns a shallow copy of the data.
|
||||
|
||||
See the Python copy module for more information on shallow
|
||||
and deep copies, https://docs.python.org/3/library/copy.html.
|
||||
|
||||
Warning: If you have subclassed MultiDiGraph to use dict-like
|
||||
objects in the data structure, those changes do not transfer
|
||||
to the MultiGraph created by this method.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> G = nx.path_graph(2) # or MultiGraph, etc
|
||||
>>> H = G.to_directed()
|
||||
>>> list(H.edges)
|
||||
[(0, 1), (1, 0)]
|
||||
>>> G2 = H.to_undirected()
|
||||
>>> list(G2.edges)
|
||||
[(0, 1)]
|
||||
"""
|
||||
graph_class = self.to_undirected_class()
|
||||
if as_view is True:
|
||||
return nx.graphviews.generic_graph_view(self, graph_class)
|
||||
# deepcopy when not a view
|
||||
G = graph_class()
|
||||
G.graph.update(deepcopy(self.graph))
|
||||
G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items())
|
||||
if reciprocal is True:
|
||||
G.add_edges_from(
|
||||
(u, v, key, deepcopy(data))
|
||||
for u, nbrs in self._adj.items()
|
||||
for v, keydict in nbrs.items()
|
||||
for key, data in keydict.items()
|
||||
if v in self._pred[u] and key in self._pred[u][v]
|
||||
)
|
||||
else:
|
||||
G.add_edges_from(
|
||||
(u, v, key, deepcopy(data))
|
||||
for u, nbrs in self._adj.items()
|
||||
for v, keydict in nbrs.items()
|
||||
for key, data in keydict.items()
|
||||
)
|
||||
return G
|
||||
|
||||
def reverse(self, copy=True):
|
||||
"""Returns the reverse of the graph.
|
||||
|
||||
The reverse is a graph with the same nodes and edges
|
||||
but with the directions of the edges reversed.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
copy : bool optional (default=True)
|
||||
If True, return a new DiGraph holding the reversed edges.
|
||||
If False, the reverse graph is created using a view of
|
||||
the original graph.
|
||||
"""
|
||||
if copy:
|
||||
H = self.__class__()
|
||||
H.graph.update(deepcopy(self.graph))
|
||||
H.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items())
|
||||
H.add_edges_from(
|
||||
(v, u, k, deepcopy(d))
|
||||
for u, v, k, d in self.edges(keys=True, data=True)
|
||||
)
|
||||
return H
|
||||
return nx.graphviews.reverse_view(self)
|
||||
1278
.CondaPkg/env/Lib/site-packages/networkx/classes/multigraph.py
vendored
Normal file
1278
.CondaPkg/env/Lib/site-packages/networkx/classes/multigraph.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1431
.CondaPkg/env/Lib/site-packages/networkx/classes/reportviews.py
vendored
Normal file
1431
.CondaPkg/env/Lib/site-packages/networkx/classes/reportviews.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
0
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__init__.py
vendored
Normal file
0
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__init__.py
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/historical_tests.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/historical_tests.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_backends.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_backends.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_coreviews.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_coreviews.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_digraph.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_digraph.cpython-311.pyc
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_filters.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_filters.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_function.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_function.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_graph.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_graph.cpython-311.pyc
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_graphviews.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_graphviews.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_multidigraph.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_multidigraph.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_multigraph.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_multigraph.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_reportviews.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_reportviews.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_special.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/__pycache__/test_special.cpython-311.pyc
vendored
Normal file
Binary file not shown.
Binary file not shown.
83
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/dispatch_interface.py
vendored
Normal file
83
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/dispatch_interface.py
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
# This file contains utilities for testing the dispatching feature
|
||||
|
||||
# A full test of all dispatchable algorithms is performed by
|
||||
# modifying the pytest invocation and setting an environment variable
|
||||
# NETWORKX_GRAPH_CONVERT=nx-loopback pytest
|
||||
# This is comprehensive, but only tests the `test_override_dispatch`
|
||||
# function in networkx.classes.backends.
|
||||
|
||||
# To test the `_dispatch` function directly, several tests scattered throughout
|
||||
# NetworkX have been augmented to test normal and dispatch mode.
|
||||
# Searching for `dispatch_interface` should locate the specific tests.
|
||||
|
||||
import networkx as nx
|
||||
from networkx import DiGraph, Graph, MultiDiGraph, MultiGraph, PlanarEmbedding
|
||||
|
||||
|
||||
class LoopbackGraph(Graph):
|
||||
__networkx_plugin__ = "nx-loopback"
|
||||
|
||||
|
||||
class LoopbackDiGraph(DiGraph):
|
||||
__networkx_plugin__ = "nx-loopback"
|
||||
|
||||
|
||||
class LoopbackMultiGraph(MultiGraph):
|
||||
__networkx_plugin__ = "nx-loopback"
|
||||
|
||||
|
||||
class LoopbackMultiDiGraph(MultiDiGraph):
|
||||
__networkx_plugin__ = "nx-loopback"
|
||||
|
||||
|
||||
class LoopbackPlanarEmbedding(PlanarEmbedding):
|
||||
__networkx_plugin__ = "nx-loopback"
|
||||
|
||||
|
||||
def convert(graph):
|
||||
if isinstance(graph, PlanarEmbedding):
|
||||
return LoopbackPlanarEmbedding(graph)
|
||||
if isinstance(graph, MultiDiGraph):
|
||||
return LoopbackMultiDiGraph(graph)
|
||||
if isinstance(graph, MultiGraph):
|
||||
return LoopbackMultiGraph(graph)
|
||||
if isinstance(graph, DiGraph):
|
||||
return LoopbackDiGraph(graph)
|
||||
if isinstance(graph, Graph):
|
||||
return LoopbackGraph(graph)
|
||||
raise TypeError(f"Unsupported type of graph: {type(graph)}")
|
||||
|
||||
|
||||
class LoopbackDispatcher:
|
||||
non_toplevel = {
|
||||
"inter_community_edges": nx.community.quality.inter_community_edges,
|
||||
"is_tournament": nx.algorithms.tournament.is_tournament,
|
||||
"mutual_weight": nx.algorithms.structuralholes.mutual_weight,
|
||||
"score_sequence": nx.algorithms.tournament.score_sequence,
|
||||
"tournament_matrix": nx.algorithms.tournament.tournament_matrix,
|
||||
}
|
||||
|
||||
def __getattr__(self, item):
|
||||
# Return the original, undecorated NetworkX algorithm
|
||||
if hasattr(nx, item):
|
||||
return getattr(nx, item)._orig_func
|
||||
if item in self.non_toplevel:
|
||||
return self.non_toplevel[item]._orig_func
|
||||
raise AttributeError(item)
|
||||
|
||||
@staticmethod
|
||||
def convert_from_nx(graph, weight=None, *, name=None):
|
||||
return graph
|
||||
|
||||
@staticmethod
|
||||
def convert_to_nx(obj, *, name=None):
|
||||
return obj
|
||||
|
||||
@staticmethod
|
||||
def on_start_tests(items):
|
||||
# Verify that items can be xfailed
|
||||
for item in items:
|
||||
assert hasattr(item, "add_marker")
|
||||
|
||||
|
||||
dispatcher = LoopbackDispatcher()
|
||||
474
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/historical_tests.py
vendored
Normal file
474
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/historical_tests.py
vendored
Normal file
@@ -0,0 +1,474 @@
|
||||
"""Original NetworkX graph tests"""
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx import convert_node_labels_to_integers as cnlti
|
||||
from networkx.utils import edges_equal, nodes_equal
|
||||
|
||||
|
||||
class HistoricalTests:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.null = nx.null_graph()
|
||||
cls.P1 = cnlti(nx.path_graph(1), first_label=1)
|
||||
cls.P3 = cnlti(nx.path_graph(3), first_label=1)
|
||||
cls.P10 = cnlti(nx.path_graph(10), first_label=1)
|
||||
cls.K1 = cnlti(nx.complete_graph(1), first_label=1)
|
||||
cls.K3 = cnlti(nx.complete_graph(3), first_label=1)
|
||||
cls.K4 = cnlti(nx.complete_graph(4), first_label=1)
|
||||
cls.K5 = cnlti(nx.complete_graph(5), first_label=1)
|
||||
cls.K10 = cnlti(nx.complete_graph(10), first_label=1)
|
||||
cls.G = nx.Graph
|
||||
|
||||
def test_name(self):
|
||||
G = self.G(name="test")
|
||||
assert G.name == "test"
|
||||
H = self.G()
|
||||
assert H.name == ""
|
||||
|
||||
# Nodes
|
||||
|
||||
def test_add_remove_node(self):
|
||||
G = self.G()
|
||||
G.add_node("A")
|
||||
assert G.has_node("A")
|
||||
G.remove_node("A")
|
||||
assert not G.has_node("A")
|
||||
|
||||
def test_nonhashable_node(self):
|
||||
# Test if a non-hashable object is in the Graph. A python dict will
|
||||
# raise a TypeError, but for a Graph class a simple False should be
|
||||
# returned (see Graph __contains__). If it cannot be a node then it is
|
||||
# not a node.
|
||||
G = self.G()
|
||||
assert not G.has_node(["A"])
|
||||
assert not G.has_node({"A": 1})
|
||||
|
||||
def test_add_nodes_from(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from(list("ABCDEFGHIJKL"))
|
||||
assert G.has_node("L")
|
||||
G.remove_nodes_from(["H", "I", "J", "K", "L"])
|
||||
G.add_nodes_from([1, 2, 3, 4])
|
||||
assert sorted(G.nodes(), key=str) == [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
]
|
||||
# test __iter__
|
||||
assert sorted(G, key=str) == [1, 2, 3, 4, "A", "B", "C", "D", "E", "F", "G"]
|
||||
|
||||
def test_contains(self):
|
||||
G = self.G()
|
||||
G.add_node("A")
|
||||
assert "A" in G
|
||||
assert [] not in G # never raise a Key or TypeError in this test
|
||||
assert {1: 1} not in G
|
||||
|
||||
def test_add_remove(self):
|
||||
# Test add_node and remove_node acting for various nbunch
|
||||
G = self.G()
|
||||
G.add_node("m")
|
||||
assert G.has_node("m")
|
||||
G.add_node("m") # no complaints
|
||||
pytest.raises(nx.NetworkXError, G.remove_node, "j")
|
||||
G.remove_node("m")
|
||||
assert list(G) == []
|
||||
|
||||
def test_nbunch_is_list(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from(list("ABCD"))
|
||||
G.add_nodes_from(self.P3) # add nbunch of nodes (nbunch=Graph)
|
||||
assert sorted(G.nodes(), key=str) == [1, 2, 3, "A", "B", "C", "D"]
|
||||
G.remove_nodes_from(self.P3) # remove nbunch of nodes (nbunch=Graph)
|
||||
assert sorted(G.nodes(), key=str) == ["A", "B", "C", "D"]
|
||||
|
||||
def test_nbunch_is_set(self):
|
||||
G = self.G()
|
||||
nbunch = set("ABCDEFGHIJKL")
|
||||
G.add_nodes_from(nbunch)
|
||||
assert G.has_node("L")
|
||||
|
||||
def test_nbunch_dict(self):
|
||||
# nbunch is a dict with nodes as keys
|
||||
G = self.G()
|
||||
nbunch = set("ABCDEFGHIJKL")
|
||||
G.add_nodes_from(nbunch)
|
||||
nbunch = {"I": "foo", "J": 2, "K": True, "L": "spam"}
|
||||
G.remove_nodes_from(nbunch)
|
||||
assert sorted(G.nodes(), key=str), ["A", "B", "C", "D", "E", "F", "G", "H"]
|
||||
|
||||
def test_nbunch_iterator(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from(["A", "B", "C", "D", "E", "F", "G", "H"])
|
||||
n_iter = self.P3.nodes()
|
||||
G.add_nodes_from(n_iter)
|
||||
assert sorted(G.nodes(), key=str) == [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"H",
|
||||
]
|
||||
n_iter = self.P3.nodes() # rebuild same iterator
|
||||
G.remove_nodes_from(n_iter) # remove nbunch of nodes (nbunch=iterator)
|
||||
assert sorted(G.nodes(), key=str) == ["A", "B", "C", "D", "E", "F", "G", "H"]
|
||||
|
||||
def test_nbunch_graph(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from(["A", "B", "C", "D", "E", "F", "G", "H"])
|
||||
nbunch = self.K3
|
||||
G.add_nodes_from(nbunch)
|
||||
assert sorted(G.nodes(), key=str), [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"H",
|
||||
]
|
||||
|
||||
# Edges
|
||||
|
||||
def test_add_edge(self):
|
||||
G = self.G()
|
||||
pytest.raises(TypeError, G.add_edge, "A")
|
||||
|
||||
G.add_edge("A", "B") # testing add_edge()
|
||||
G.add_edge("A", "B") # should fail silently
|
||||
assert G.has_edge("A", "B")
|
||||
assert not G.has_edge("A", "C")
|
||||
assert G.has_edge(*("A", "B"))
|
||||
if G.is_directed():
|
||||
assert not G.has_edge("B", "A")
|
||||
else:
|
||||
# G is undirected, so B->A is an edge
|
||||
assert G.has_edge("B", "A")
|
||||
|
||||
G.add_edge("A", "C") # test directedness
|
||||
G.add_edge("C", "A")
|
||||
G.remove_edge("C", "A")
|
||||
if G.is_directed():
|
||||
assert G.has_edge("A", "C")
|
||||
else:
|
||||
assert not G.has_edge("A", "C")
|
||||
assert not G.has_edge("C", "A")
|
||||
|
||||
def test_self_loop(self):
|
||||
G = self.G()
|
||||
G.add_edge("A", "A") # test self loops
|
||||
assert G.has_edge("A", "A")
|
||||
G.remove_edge("A", "A")
|
||||
G.add_edge("X", "X")
|
||||
assert G.has_node("X")
|
||||
G.remove_node("X")
|
||||
G.add_edge("A", "Z") # should add the node silently
|
||||
assert G.has_node("Z")
|
||||
|
||||
def test_add_edges_from(self):
|
||||
G = self.G()
|
||||
G.add_edges_from([("B", "C")]) # test add_edges_from()
|
||||
assert G.has_edge("B", "C")
|
||||
if G.is_directed():
|
||||
assert not G.has_edge("C", "B")
|
||||
else:
|
||||
assert G.has_edge("C", "B") # undirected
|
||||
|
||||
G.add_edges_from([("D", "F"), ("B", "D")])
|
||||
assert G.has_edge("D", "F")
|
||||
assert G.has_edge("B", "D")
|
||||
|
||||
if G.is_directed():
|
||||
assert not G.has_edge("D", "B")
|
||||
else:
|
||||
assert G.has_edge("D", "B") # undirected
|
||||
|
||||
def test_add_edges_from2(self):
|
||||
G = self.G()
|
||||
# after failing silently, should add 2nd edge
|
||||
G.add_edges_from([tuple("IJ"), list("KK"), tuple("JK")])
|
||||
assert G.has_edge(*("I", "J"))
|
||||
assert G.has_edge(*("K", "K"))
|
||||
assert G.has_edge(*("J", "K"))
|
||||
if G.is_directed():
|
||||
assert not G.has_edge(*("K", "J"))
|
||||
else:
|
||||
assert G.has_edge(*("K", "J"))
|
||||
|
||||
def test_add_edges_from3(self):
|
||||
G = self.G()
|
||||
G.add_edges_from(zip(list("ACD"), list("CDE")))
|
||||
assert G.has_edge("D", "E")
|
||||
assert not G.has_edge("E", "C")
|
||||
|
||||
def test_remove_edge(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from([1, 2, 3, "A", "B", "C", "D", "E", "F", "G", "H"])
|
||||
|
||||
G.add_edges_from(zip(list("MNOP"), list("NOPM")))
|
||||
assert G.has_edge("O", "P")
|
||||
assert G.has_edge("P", "M")
|
||||
G.remove_node("P") # tests remove_node()'s handling of edges.
|
||||
assert not G.has_edge("P", "M")
|
||||
pytest.raises(TypeError, G.remove_edge, "M")
|
||||
|
||||
G.add_edge("N", "M")
|
||||
assert G.has_edge("M", "N")
|
||||
G.remove_edge("M", "N")
|
||||
assert not G.has_edge("M", "N")
|
||||
|
||||
# self loop fails silently
|
||||
G.remove_edges_from([list("HI"), list("DF"), tuple("KK"), tuple("JK")])
|
||||
assert not G.has_edge("H", "I")
|
||||
assert not G.has_edge("J", "K")
|
||||
G.remove_edges_from([list("IJ"), list("KK"), list("JK")])
|
||||
assert not G.has_edge("I", "J")
|
||||
G.remove_nodes_from(set("ZEFHIMNO"))
|
||||
G.add_edge("J", "K")
|
||||
|
||||
def test_edges_nbunch(self):
|
||||
# Test G.edges(nbunch) with various forms of nbunch
|
||||
G = self.G()
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")])
|
||||
# node not in nbunch should be quietly ignored
|
||||
pytest.raises(nx.NetworkXError, G.edges, 6)
|
||||
assert list(G.edges("Z")) == [] # iterable non-node
|
||||
# nbunch can be an empty list
|
||||
assert list(G.edges([])) == []
|
||||
if G.is_directed():
|
||||
elist = [("A", "B"), ("A", "C"), ("B", "D")]
|
||||
else:
|
||||
elist = [("A", "B"), ("A", "C"), ("B", "C"), ("B", "D")]
|
||||
# nbunch can be a list
|
||||
assert edges_equal(list(G.edges(["A", "B"])), elist)
|
||||
# nbunch can be a set
|
||||
assert edges_equal(G.edges({"A", "B"}), elist)
|
||||
# nbunch can be a graph
|
||||
G1 = self.G()
|
||||
G1.add_nodes_from("AB")
|
||||
assert edges_equal(G.edges(G1), elist)
|
||||
# nbunch can be a dict with nodes as keys
|
||||
ndict = {"A": "thing1", "B": "thing2"}
|
||||
assert edges_equal(G.edges(ndict), elist)
|
||||
# nbunch can be a single node
|
||||
assert edges_equal(list(G.edges("A")), [("A", "B"), ("A", "C")])
|
||||
assert nodes_equal(sorted(G), ["A", "B", "C", "D"])
|
||||
|
||||
# nbunch can be nothing (whole graph)
|
||||
assert edges_equal(
|
||||
list(G.edges()),
|
||||
[("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")],
|
||||
)
|
||||
|
||||
def test_degree(self):
|
||||
G = self.G()
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")])
|
||||
assert G.degree("A") == 2
|
||||
|
||||
# degree of single node in iterable container must return dict
|
||||
assert list(G.degree(["A"])) == [("A", 2)]
|
||||
assert sorted(d for n, d in G.degree(["A", "B"])) == [2, 3]
|
||||
assert sorted(d for n, d in G.degree()) == [2, 2, 3, 3]
|
||||
|
||||
def test_degree2(self):
|
||||
H = self.G()
|
||||
H.add_edges_from([(1, 24), (1, 2)])
|
||||
assert sorted(d for n, d in H.degree([1, 24])) == [1, 2]
|
||||
|
||||
def test_degree_graph(self):
|
||||
P3 = nx.path_graph(3)
|
||||
P5 = nx.path_graph(5)
|
||||
# silently ignore nodes not in P3
|
||||
assert dict(d for n, d in P3.degree(["A", "B"])) == {}
|
||||
# nbunch can be a graph
|
||||
assert sorted(d for n, d in P5.degree(P3)) == [1, 2, 2]
|
||||
# nbunch can be a graph that's way too big
|
||||
assert sorted(d for n, d in P3.degree(P5)) == [1, 1, 2]
|
||||
assert list(P5.degree([])) == []
|
||||
assert dict(P5.degree([])) == {}
|
||||
|
||||
def test_null(self):
|
||||
null = nx.null_graph()
|
||||
assert list(null.degree()) == []
|
||||
assert dict(null.degree()) == {}
|
||||
|
||||
def test_order_size(self):
|
||||
G = self.G()
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")])
|
||||
assert G.order() == 4
|
||||
assert G.size() == 5
|
||||
assert G.number_of_edges() == 5
|
||||
assert G.number_of_edges("A", "B") == 1
|
||||
assert G.number_of_edges("A", "D") == 0
|
||||
|
||||
def test_copy(self):
|
||||
G = self.G()
|
||||
H = G.copy() # copy
|
||||
assert H.adj == G.adj
|
||||
assert H.name == G.name
|
||||
assert H is not G
|
||||
|
||||
def test_subgraph(self):
|
||||
G = self.G()
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")])
|
||||
SG = G.subgraph(["A", "B", "D"])
|
||||
assert nodes_equal(list(SG), ["A", "B", "D"])
|
||||
assert edges_equal(list(SG.edges()), [("A", "B"), ("B", "D")])
|
||||
|
||||
def test_to_directed(self):
|
||||
G = self.G()
|
||||
if not G.is_directed():
|
||||
G.add_edges_from(
|
||||
[("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")]
|
||||
)
|
||||
|
||||
DG = G.to_directed()
|
||||
assert DG is not G # directed copy or copy
|
||||
|
||||
assert DG.is_directed()
|
||||
assert DG.name == G.name
|
||||
assert DG.adj == G.adj
|
||||
assert sorted(DG.out_edges(list("AB"))) == [
|
||||
("A", "B"),
|
||||
("A", "C"),
|
||||
("B", "A"),
|
||||
("B", "C"),
|
||||
("B", "D"),
|
||||
]
|
||||
DG.remove_edge("A", "B")
|
||||
assert DG.has_edge("B", "A") # this removes B-A but not A-B
|
||||
assert not DG.has_edge("A", "B")
|
||||
|
||||
def test_to_undirected(self):
|
||||
G = self.G()
|
||||
if G.is_directed():
|
||||
G.add_edges_from(
|
||||
[("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")]
|
||||
)
|
||||
UG = G.to_undirected() # to_undirected
|
||||
assert UG is not G
|
||||
assert not UG.is_directed()
|
||||
assert G.is_directed()
|
||||
assert UG.name == G.name
|
||||
assert UG.adj != G.adj
|
||||
assert sorted(UG.edges(list("AB"))) == [
|
||||
("A", "B"),
|
||||
("A", "C"),
|
||||
("B", "C"),
|
||||
("B", "D"),
|
||||
]
|
||||
assert sorted(UG.edges(["A", "B"])) == [
|
||||
("A", "B"),
|
||||
("A", "C"),
|
||||
("B", "C"),
|
||||
("B", "D"),
|
||||
]
|
||||
UG.remove_edge("A", "B")
|
||||
assert not UG.has_edge("B", "A")
|
||||
assert not UG.has_edge("A", "B")
|
||||
|
||||
def test_neighbors(self):
|
||||
G = self.G()
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")])
|
||||
G.add_nodes_from("GJK")
|
||||
assert sorted(G["A"]) == ["B", "C"]
|
||||
assert sorted(G.neighbors("A")) == ["B", "C"]
|
||||
assert sorted(G.neighbors("A")) == ["B", "C"]
|
||||
assert sorted(G.neighbors("G")) == []
|
||||
pytest.raises(nx.NetworkXError, G.neighbors, "j")
|
||||
|
||||
def test_iterators(self):
|
||||
G = self.G()
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")])
|
||||
G.add_nodes_from("GJK")
|
||||
assert sorted(G.nodes()) == ["A", "B", "C", "D", "G", "J", "K"]
|
||||
assert edges_equal(
|
||||
G.edges(), [("A", "B"), ("A", "C"), ("B", "D"), ("C", "B"), ("C", "D")]
|
||||
)
|
||||
|
||||
assert sorted(v for k, v in G.degree()) == [0, 0, 0, 2, 2, 3, 3]
|
||||
assert sorted(G.degree(), key=str) == [
|
||||
("A", 2),
|
||||
("B", 3),
|
||||
("C", 3),
|
||||
("D", 2),
|
||||
("G", 0),
|
||||
("J", 0),
|
||||
("K", 0),
|
||||
]
|
||||
assert sorted(G.neighbors("A")) == ["B", "C"]
|
||||
pytest.raises(nx.NetworkXError, G.neighbors, "X")
|
||||
G.clear()
|
||||
assert nx.number_of_nodes(G) == 0
|
||||
assert nx.number_of_edges(G) == 0
|
||||
|
||||
def test_null_subgraph(self):
|
||||
# Subgraph of a null graph is a null graph
|
||||
nullgraph = nx.null_graph()
|
||||
G = nx.null_graph()
|
||||
H = G.subgraph([])
|
||||
assert nx.is_isomorphic(H, nullgraph)
|
||||
|
||||
def test_empty_subgraph(self):
|
||||
# Subgraph of an empty graph is an empty graph. test 1
|
||||
nullgraph = nx.null_graph()
|
||||
E5 = nx.empty_graph(5)
|
||||
E10 = nx.empty_graph(10)
|
||||
H = E10.subgraph([])
|
||||
assert nx.is_isomorphic(H, nullgraph)
|
||||
H = E10.subgraph([1, 2, 3, 4, 5])
|
||||
assert nx.is_isomorphic(H, E5)
|
||||
|
||||
def test_complete_subgraph(self):
|
||||
# Subgraph of a complete graph is a complete graph
|
||||
K1 = nx.complete_graph(1)
|
||||
K3 = nx.complete_graph(3)
|
||||
K5 = nx.complete_graph(5)
|
||||
H = K5.subgraph([1, 2, 3])
|
||||
assert nx.is_isomorphic(H, K3)
|
||||
|
||||
def test_subgraph_nbunch(self):
|
||||
nullgraph = nx.null_graph()
|
||||
K1 = nx.complete_graph(1)
|
||||
K3 = nx.complete_graph(3)
|
||||
K5 = nx.complete_graph(5)
|
||||
# Test G.subgraph(nbunch), where nbunch is a single node
|
||||
H = K5.subgraph(1)
|
||||
assert nx.is_isomorphic(H, K1)
|
||||
# Test G.subgraph(nbunch), where nbunch is a set
|
||||
H = K5.subgraph({1})
|
||||
assert nx.is_isomorphic(H, K1)
|
||||
# Test G.subgraph(nbunch), where nbunch is an iterator
|
||||
H = K5.subgraph(iter(K3))
|
||||
assert nx.is_isomorphic(H, K3)
|
||||
# Test G.subgraph(nbunch), where nbunch is another graph
|
||||
H = K5.subgraph(K3)
|
||||
assert nx.is_isomorphic(H, K3)
|
||||
H = K5.subgraph([9])
|
||||
assert nx.is_isomorphic(H, nullgraph)
|
||||
|
||||
def test_node_tuple_issue(self):
|
||||
H = self.G()
|
||||
# Test error handling of tuple as a node
|
||||
pytest.raises(nx.NetworkXError, H.remove_node, (1, 2))
|
||||
H.remove_nodes_from([(1, 2)]) # no error
|
||||
pytest.raises(nx.NetworkXError, H.neighbors, (1, 2))
|
||||
14
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_backends.py
vendored
Normal file
14
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_backends.py
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
|
||||
pytest.importorskip("scipy")
|
||||
pytest.importorskip("numpy")
|
||||
|
||||
|
||||
def test_dispatch_kwds_vs_args():
|
||||
G = nx.path_graph(4)
|
||||
nx.pagerank(G)
|
||||
nx.pagerank(G=G)
|
||||
with pytest.raises(TypeError):
|
||||
nx.pagerank()
|
||||
362
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_coreviews.py
vendored
Normal file
362
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_coreviews.py
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
import pickle
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
|
||||
|
||||
class TestAtlasView:
|
||||
# node->data
|
||||
def setup_method(self):
|
||||
self.d = {0: {"color": "blue", "weight": 1.2}, 1: {}, 2: {"color": 1}}
|
||||
self.av = nx.classes.coreviews.AtlasView(self.d)
|
||||
|
||||
def test_pickle(self):
|
||||
view = self.av
|
||||
pview = pickle.loads(pickle.dumps(view, -1))
|
||||
assert view == pview
|
||||
assert view.__slots__ == pview.__slots__
|
||||
pview = pickle.loads(pickle.dumps(view))
|
||||
assert view == pview
|
||||
assert view.__slots__ == pview.__slots__
|
||||
|
||||
def test_len(self):
|
||||
assert len(self.av) == len(self.d)
|
||||
|
||||
def test_iter(self):
|
||||
assert list(self.av) == list(self.d)
|
||||
|
||||
def test_getitem(self):
|
||||
assert self.av[1] is self.d[1]
|
||||
assert self.av[2]["color"] == 1
|
||||
pytest.raises(KeyError, self.av.__getitem__, 3)
|
||||
|
||||
def test_copy(self):
|
||||
avcopy = self.av.copy()
|
||||
assert avcopy[0] == self.av[0]
|
||||
assert avcopy == self.av
|
||||
assert avcopy[0] is not self.av[0]
|
||||
assert avcopy is not self.av
|
||||
avcopy[5] = {}
|
||||
assert avcopy != self.av
|
||||
|
||||
avcopy[0]["ht"] = 4
|
||||
assert avcopy[0] != self.av[0]
|
||||
self.av[0]["ht"] = 4
|
||||
assert avcopy[0] == self.av[0]
|
||||
del self.av[0]["ht"]
|
||||
|
||||
assert not hasattr(self.av, "__setitem__")
|
||||
|
||||
def test_items(self):
|
||||
assert sorted(self.av.items()) == sorted(self.d.items())
|
||||
|
||||
def test_str(self):
|
||||
out = str(self.d)
|
||||
assert str(self.av) == out
|
||||
|
||||
def test_repr(self):
|
||||
out = "AtlasView(" + str(self.d) + ")"
|
||||
assert repr(self.av) == out
|
||||
|
||||
|
||||
class TestAdjacencyView:
|
||||
# node->nbr->data
|
||||
def setup_method(self):
|
||||
dd = {"color": "blue", "weight": 1.2}
|
||||
self.nd = {0: dd, 1: {}, 2: {"color": 1}}
|
||||
self.adj = {3: self.nd, 0: {3: dd}, 1: {}, 2: {3: {"color": 1}}}
|
||||
self.adjview = nx.classes.coreviews.AdjacencyView(self.adj)
|
||||
|
||||
def test_pickle(self):
|
||||
view = self.adjview
|
||||
pview = pickle.loads(pickle.dumps(view, -1))
|
||||
assert view == pview
|
||||
assert view.__slots__ == pview.__slots__
|
||||
|
||||
def test_len(self):
|
||||
assert len(self.adjview) == len(self.adj)
|
||||
|
||||
def test_iter(self):
|
||||
assert list(self.adjview) == list(self.adj)
|
||||
|
||||
def test_getitem(self):
|
||||
assert self.adjview[1] is not self.adj[1]
|
||||
assert self.adjview[3][0] is self.adjview[0][3]
|
||||
assert self.adjview[2][3]["color"] == 1
|
||||
pytest.raises(KeyError, self.adjview.__getitem__, 4)
|
||||
|
||||
def test_copy(self):
|
||||
avcopy = self.adjview.copy()
|
||||
assert avcopy[0] == self.adjview[0]
|
||||
assert avcopy[0] is not self.adjview[0]
|
||||
|
||||
avcopy[2][3]["ht"] = 4
|
||||
assert avcopy[2] != self.adjview[2]
|
||||
self.adjview[2][3]["ht"] = 4
|
||||
assert avcopy[2] == self.adjview[2]
|
||||
del self.adjview[2][3]["ht"]
|
||||
|
||||
assert not hasattr(self.adjview, "__setitem__")
|
||||
|
||||
def test_items(self):
|
||||
view_items = sorted((n, dict(d)) for n, d in self.adjview.items())
|
||||
assert view_items == sorted(self.adj.items())
|
||||
|
||||
def test_str(self):
|
||||
out = str(dict(self.adj))
|
||||
assert str(self.adjview) == out
|
||||
|
||||
def test_repr(self):
|
||||
out = self.adjview.__class__.__name__ + "(" + str(self.adj) + ")"
|
||||
assert repr(self.adjview) == out
|
||||
|
||||
|
||||
class TestMultiAdjacencyView(TestAdjacencyView):
|
||||
# node->nbr->key->data
|
||||
def setup_method(self):
|
||||
dd = {"color": "blue", "weight": 1.2}
|
||||
self.kd = {0: dd, 1: {}, 2: {"color": 1}}
|
||||
self.nd = {3: self.kd, 0: {3: dd}, 1: {0: {}}, 2: {3: {"color": 1}}}
|
||||
self.adj = {3: self.nd, 0: {3: {3: dd}}, 1: {}, 2: {3: {8: {}}}}
|
||||
self.adjview = nx.classes.coreviews.MultiAdjacencyView(self.adj)
|
||||
|
||||
def test_getitem(self):
|
||||
assert self.adjview[1] is not self.adj[1]
|
||||
assert self.adjview[3][0][3] is self.adjview[0][3][3]
|
||||
assert self.adjview[3][2][3]["color"] == 1
|
||||
pytest.raises(KeyError, self.adjview.__getitem__, 4)
|
||||
|
||||
def test_copy(self):
|
||||
avcopy = self.adjview.copy()
|
||||
assert avcopy[0] == self.adjview[0]
|
||||
assert avcopy[0] is not self.adjview[0]
|
||||
|
||||
avcopy[2][3][8]["ht"] = 4
|
||||
assert avcopy[2] != self.adjview[2]
|
||||
self.adjview[2][3][8]["ht"] = 4
|
||||
assert avcopy[2] == self.adjview[2]
|
||||
del self.adjview[2][3][8]["ht"]
|
||||
|
||||
assert not hasattr(self.adjview, "__setitem__")
|
||||
|
||||
|
||||
class TestUnionAtlas:
|
||||
# node->data
|
||||
def setup_method(self):
|
||||
self.s = {0: {"color": "blue", "weight": 1.2}, 1: {}, 2: {"color": 1}}
|
||||
self.p = {3: {"color": "blue", "weight": 1.2}, 4: {}, 2: {"watch": 2}}
|
||||
self.av = nx.classes.coreviews.UnionAtlas(self.s, self.p)
|
||||
|
||||
def test_pickle(self):
|
||||
view = self.av
|
||||
pview = pickle.loads(pickle.dumps(view, -1))
|
||||
assert view == pview
|
||||
assert view.__slots__ == pview.__slots__
|
||||
|
||||
def test_len(self):
|
||||
assert len(self.av) == len(self.s.keys() | self.p.keys()) == 5
|
||||
|
||||
def test_iter(self):
|
||||
assert set(self.av) == set(self.s) | set(self.p)
|
||||
|
||||
def test_getitem(self):
|
||||
assert self.av[0] is self.s[0]
|
||||
assert self.av[4] is self.p[4]
|
||||
assert self.av[2]["color"] == 1
|
||||
pytest.raises(KeyError, self.av[2].__getitem__, "watch")
|
||||
pytest.raises(KeyError, self.av.__getitem__, 8)
|
||||
|
||||
def test_copy(self):
|
||||
avcopy = self.av.copy()
|
||||
assert avcopy[0] == self.av[0]
|
||||
assert avcopy[0] is not self.av[0]
|
||||
assert avcopy is not self.av
|
||||
avcopy[5] = {}
|
||||
assert avcopy != self.av
|
||||
|
||||
avcopy[0]["ht"] = 4
|
||||
assert avcopy[0] != self.av[0]
|
||||
self.av[0]["ht"] = 4
|
||||
assert avcopy[0] == self.av[0]
|
||||
del self.av[0]["ht"]
|
||||
|
||||
assert not hasattr(self.av, "__setitem__")
|
||||
|
||||
def test_items(self):
|
||||
expected = dict(self.p.items())
|
||||
expected.update(self.s)
|
||||
assert sorted(self.av.items()) == sorted(expected.items())
|
||||
|
||||
def test_str(self):
|
||||
out = str(dict(self.av))
|
||||
assert str(self.av) == out
|
||||
|
||||
def test_repr(self):
|
||||
out = f"{self.av.__class__.__name__}({self.s}, {self.p})"
|
||||
assert repr(self.av) == out
|
||||
|
||||
|
||||
class TestUnionAdjacency:
|
||||
# node->nbr->data
|
||||
def setup_method(self):
|
||||
dd = {"color": "blue", "weight": 1.2}
|
||||
self.nd = {0: dd, 1: {}, 2: {"color": 1}}
|
||||
self.s = {3: self.nd, 0: {}, 1: {}, 2: {3: {"color": 1}}}
|
||||
self.p = {3: {}, 0: {3: dd}, 1: {0: {}}, 2: {1: {"color": 1}}}
|
||||
self.adjview = nx.classes.coreviews.UnionAdjacency(self.s, self.p)
|
||||
|
||||
def test_pickle(self):
|
||||
view = self.adjview
|
||||
pview = pickle.loads(pickle.dumps(view, -1))
|
||||
assert view == pview
|
||||
assert view.__slots__ == pview.__slots__
|
||||
|
||||
def test_len(self):
|
||||
assert len(self.adjview) == len(self.s)
|
||||
|
||||
def test_iter(self):
|
||||
assert sorted(self.adjview) == sorted(self.s)
|
||||
|
||||
def test_getitem(self):
|
||||
assert self.adjview[1] is not self.s[1]
|
||||
assert self.adjview[3][0] is self.adjview[0][3]
|
||||
assert self.adjview[2][3]["color"] == 1
|
||||
pytest.raises(KeyError, self.adjview.__getitem__, 4)
|
||||
|
||||
def test_copy(self):
|
||||
avcopy = self.adjview.copy()
|
||||
assert avcopy[0] == self.adjview[0]
|
||||
assert avcopy[0] is not self.adjview[0]
|
||||
|
||||
avcopy[2][3]["ht"] = 4
|
||||
assert avcopy[2] != self.adjview[2]
|
||||
self.adjview[2][3]["ht"] = 4
|
||||
assert avcopy[2] == self.adjview[2]
|
||||
del self.adjview[2][3]["ht"]
|
||||
|
||||
assert not hasattr(self.adjview, "__setitem__")
|
||||
|
||||
def test_str(self):
|
||||
out = str(dict(self.adjview))
|
||||
assert str(self.adjview) == out
|
||||
|
||||
def test_repr(self):
|
||||
clsname = self.adjview.__class__.__name__
|
||||
out = f"{clsname}({self.s}, {self.p})"
|
||||
assert repr(self.adjview) == out
|
||||
|
||||
|
||||
class TestUnionMultiInner(TestUnionAdjacency):
|
||||
# nbr->key->data
|
||||
def setup_method(self):
|
||||
dd = {"color": "blue", "weight": 1.2}
|
||||
self.kd = {7: {}, "ekey": {}, 9: {"color": 1}}
|
||||
self.s = {3: self.kd, 0: {7: dd}, 1: {}, 2: {"key": {"color": 1}}}
|
||||
self.p = {3: {}, 0: {3: dd}, 1: {}, 2: {1: {"span": 2}}}
|
||||
self.adjview = nx.classes.coreviews.UnionMultiInner(self.s, self.p)
|
||||
|
||||
def test_len(self):
|
||||
assert len(self.adjview) == len(self.s.keys() | self.p.keys()) == 4
|
||||
|
||||
def test_getitem(self):
|
||||
assert self.adjview[1] is not self.s[1]
|
||||
assert self.adjview[0][7] is self.adjview[0][3]
|
||||
assert self.adjview[2]["key"]["color"] == 1
|
||||
assert self.adjview[2][1]["span"] == 2
|
||||
pytest.raises(KeyError, self.adjview.__getitem__, 4)
|
||||
pytest.raises(KeyError, self.adjview[1].__getitem__, "key")
|
||||
|
||||
def test_copy(self):
|
||||
avcopy = self.adjview.copy()
|
||||
assert avcopy[0] == self.adjview[0]
|
||||
assert avcopy[0] is not self.adjview[0]
|
||||
|
||||
avcopy[2][1]["width"] = 8
|
||||
assert avcopy[2] != self.adjview[2]
|
||||
self.adjview[2][1]["width"] = 8
|
||||
assert avcopy[2] == self.adjview[2]
|
||||
del self.adjview[2][1]["width"]
|
||||
|
||||
assert not hasattr(self.adjview, "__setitem__")
|
||||
assert hasattr(avcopy, "__setitem__")
|
||||
|
||||
|
||||
class TestUnionMultiAdjacency(TestUnionAdjacency):
|
||||
# node->nbr->key->data
|
||||
def setup_method(self):
|
||||
dd = {"color": "blue", "weight": 1.2}
|
||||
self.kd = {7: {}, 8: {}, 9: {"color": 1}}
|
||||
self.nd = {3: self.kd, 0: {9: dd}, 1: {8: {}}, 2: {9: {"color": 1}}}
|
||||
self.s = {3: self.nd, 0: {3: {7: dd}}, 1: {}, 2: {3: {8: {}}}}
|
||||
self.p = {3: {}, 0: {3: {9: dd}}, 1: {}, 2: {1: {8: {}}}}
|
||||
self.adjview = nx.classes.coreviews.UnionMultiAdjacency(self.s, self.p)
|
||||
|
||||
def test_getitem(self):
|
||||
assert self.adjview[1] is not self.s[1]
|
||||
assert self.adjview[3][0][9] is self.adjview[0][3][9]
|
||||
assert self.adjview[3][2][9]["color"] == 1
|
||||
pytest.raises(KeyError, self.adjview.__getitem__, 4)
|
||||
|
||||
def test_copy(self):
|
||||
avcopy = self.adjview.copy()
|
||||
assert avcopy[0] == self.adjview[0]
|
||||
assert avcopy[0] is not self.adjview[0]
|
||||
|
||||
avcopy[2][3][8]["ht"] = 4
|
||||
assert avcopy[2] != self.adjview[2]
|
||||
self.adjview[2][3][8]["ht"] = 4
|
||||
assert avcopy[2] == self.adjview[2]
|
||||
del self.adjview[2][3][8]["ht"]
|
||||
|
||||
assert not hasattr(self.adjview, "__setitem__")
|
||||
assert hasattr(avcopy, "__setitem__")
|
||||
|
||||
|
||||
class TestFilteredGraphs:
|
||||
def setup_method(self):
|
||||
self.Graphs = [nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph]
|
||||
|
||||
def test_hide_show_nodes(self):
|
||||
SubGraph = nx.graphviews.subgraph_view
|
||||
for Graph in self.Graphs:
|
||||
G = nx.path_graph(4, Graph)
|
||||
SG = G.subgraph([2, 3])
|
||||
RG = SubGraph(G, nx.filters.hide_nodes([0, 1]))
|
||||
assert SG.nodes == RG.nodes
|
||||
assert SG.edges == RG.edges
|
||||
SGC = SG.copy()
|
||||
RGC = RG.copy()
|
||||
assert SGC.nodes == RGC.nodes
|
||||
assert SGC.edges == RGC.edges
|
||||
|
||||
def test_str_repr(self):
|
||||
SubGraph = nx.graphviews.subgraph_view
|
||||
for Graph in self.Graphs:
|
||||
G = nx.path_graph(4, Graph)
|
||||
SG = G.subgraph([2, 3])
|
||||
RG = SubGraph(G, nx.filters.hide_nodes([0, 1]))
|
||||
str(SG.adj)
|
||||
str(RG.adj)
|
||||
repr(SG.adj)
|
||||
repr(RG.adj)
|
||||
str(SG.adj[2])
|
||||
str(RG.adj[2])
|
||||
repr(SG.adj[2])
|
||||
repr(RG.adj[2])
|
||||
|
||||
def test_copy(self):
|
||||
SubGraph = nx.graphviews.subgraph_view
|
||||
for Graph in self.Graphs:
|
||||
G = nx.path_graph(4, Graph)
|
||||
SG = G.subgraph([2, 3])
|
||||
RG = SubGraph(G, nx.filters.hide_nodes([0, 1]))
|
||||
RsG = SubGraph(G, nx.filters.show_nodes([2, 3]))
|
||||
assert G.adj.copy() == G.adj
|
||||
assert G.adj[2].copy() == G.adj[2]
|
||||
assert SG.adj.copy() == SG.adj
|
||||
assert SG.adj[2].copy() == SG.adj[2]
|
||||
assert RG.adj.copy() == RG.adj
|
||||
assert RG.adj[2].copy() == RG.adj[2]
|
||||
assert RsG.adj.copy() == RsG.adj
|
||||
assert RsG.adj[2].copy() == RsG.adj[2]
|
||||
331
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_digraph.py
vendored
Normal file
331
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_digraph.py
vendored
Normal file
@@ -0,0 +1,331 @@
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import nodes_equal
|
||||
|
||||
from .test_graph import BaseAttrGraphTester, BaseGraphTester
|
||||
from .test_graph import TestEdgeSubgraph as _TestGraphEdgeSubgraph
|
||||
from .test_graph import TestGraph as _TestGraph
|
||||
|
||||
|
||||
class BaseDiGraphTester(BaseGraphTester):
|
||||
def test_has_successor(self):
|
||||
G = self.K3
|
||||
assert G.has_successor(0, 1)
|
||||
assert not G.has_successor(0, -1)
|
||||
|
||||
def test_successors(self):
|
||||
G = self.K3
|
||||
assert sorted(G.successors(0)) == [1, 2]
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.successors(-1)
|
||||
|
||||
def test_has_predecessor(self):
|
||||
G = self.K3
|
||||
assert G.has_predecessor(0, 1)
|
||||
assert not G.has_predecessor(0, -1)
|
||||
|
||||
def test_predecessors(self):
|
||||
G = self.K3
|
||||
assert sorted(G.predecessors(0)) == [1, 2]
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.predecessors(-1)
|
||||
|
||||
def test_edges(self):
|
||||
G = self.K3
|
||||
assert sorted(G.edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
|
||||
assert sorted(G.edges(0)) == [(0, 1), (0, 2)]
|
||||
assert sorted(G.edges([0, 1])) == [(0, 1), (0, 2), (1, 0), (1, 2)]
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.edges(-1)
|
||||
|
||||
def test_out_edges(self):
|
||||
G = self.K3
|
||||
assert sorted(G.out_edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
|
||||
assert sorted(G.out_edges(0)) == [(0, 1), (0, 2)]
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.out_edges(-1)
|
||||
|
||||
def test_out_edges_dir(self):
|
||||
G = self.P3
|
||||
assert sorted(G.out_edges()) == [(0, 1), (1, 2)]
|
||||
assert sorted(G.out_edges(0)) == [(0, 1)]
|
||||
assert sorted(G.out_edges(2)) == []
|
||||
|
||||
def test_out_edges_data(self):
|
||||
G = nx.DiGraph([(0, 1, {"data": 0}), (1, 0, {})])
|
||||
assert sorted(G.out_edges(data=True)) == [(0, 1, {"data": 0}), (1, 0, {})]
|
||||
assert sorted(G.out_edges(0, data=True)) == [(0, 1, {"data": 0})]
|
||||
assert sorted(G.out_edges(data="data")) == [(0, 1, 0), (1, 0, None)]
|
||||
assert sorted(G.out_edges(0, data="data")) == [(0, 1, 0)]
|
||||
|
||||
def test_in_edges_dir(self):
|
||||
G = self.P3
|
||||
assert sorted(G.in_edges()) == [(0, 1), (1, 2)]
|
||||
assert sorted(G.in_edges(0)) == []
|
||||
assert sorted(G.in_edges(2)) == [(1, 2)]
|
||||
|
||||
def test_in_edges_data(self):
|
||||
G = nx.DiGraph([(0, 1, {"data": 0}), (1, 0, {})])
|
||||
assert sorted(G.in_edges(data=True)) == [(0, 1, {"data": 0}), (1, 0, {})]
|
||||
assert sorted(G.in_edges(1, data=True)) == [(0, 1, {"data": 0})]
|
||||
assert sorted(G.in_edges(data="data")) == [(0, 1, 0), (1, 0, None)]
|
||||
assert sorted(G.in_edges(1, data="data")) == [(0, 1, 0)]
|
||||
|
||||
def test_degree(self):
|
||||
G = self.K3
|
||||
assert sorted(G.degree()) == [(0, 4), (1, 4), (2, 4)]
|
||||
assert dict(G.degree()) == {0: 4, 1: 4, 2: 4}
|
||||
assert G.degree(0) == 4
|
||||
assert list(G.degree(iter([0]))) == [(0, 4)] # run through iterator
|
||||
|
||||
def test_in_degree(self):
|
||||
G = self.K3
|
||||
assert sorted(G.in_degree()) == [(0, 2), (1, 2), (2, 2)]
|
||||
assert dict(G.in_degree()) == {0: 2, 1: 2, 2: 2}
|
||||
assert G.in_degree(0) == 2
|
||||
assert list(G.in_degree(iter([0]))) == [(0, 2)] # run through iterator
|
||||
|
||||
def test_out_degree(self):
|
||||
G = self.K3
|
||||
assert sorted(G.out_degree()) == [(0, 2), (1, 2), (2, 2)]
|
||||
assert dict(G.out_degree()) == {0: 2, 1: 2, 2: 2}
|
||||
assert G.out_degree(0) == 2
|
||||
assert list(G.out_degree(iter([0]))) == [(0, 2)]
|
||||
|
||||
def test_size(self):
|
||||
G = self.K3
|
||||
assert G.size() == 6
|
||||
assert G.number_of_edges() == 6
|
||||
|
||||
def test_to_undirected_reciprocal(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 2)
|
||||
assert G.to_undirected().has_edge(1, 2)
|
||||
assert not G.to_undirected(reciprocal=True).has_edge(1, 2)
|
||||
G.add_edge(2, 1)
|
||||
assert G.to_undirected(reciprocal=True).has_edge(1, 2)
|
||||
|
||||
def test_reverse_copy(self):
|
||||
G = nx.DiGraph([(0, 1), (1, 2)])
|
||||
R = G.reverse()
|
||||
assert sorted(R.edges()) == [(1, 0), (2, 1)]
|
||||
R.remove_edge(1, 0)
|
||||
assert sorted(R.edges()) == [(2, 1)]
|
||||
assert sorted(G.edges()) == [(0, 1), (1, 2)]
|
||||
|
||||
def test_reverse_nocopy(self):
|
||||
G = nx.DiGraph([(0, 1), (1, 2)])
|
||||
R = G.reverse(copy=False)
|
||||
assert sorted(R.edges()) == [(1, 0), (2, 1)]
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
R.remove_edge(1, 0)
|
||||
|
||||
def test_reverse_hashable(self):
|
||||
class Foo:
|
||||
pass
|
||||
|
||||
x = Foo()
|
||||
y = Foo()
|
||||
G = nx.DiGraph()
|
||||
G.add_edge(x, y)
|
||||
assert nodes_equal(G.nodes(), G.reverse().nodes())
|
||||
assert [(y, x)] == list(G.reverse().edges())
|
||||
|
||||
def test_di_cache_reset(self):
|
||||
G = self.K3.copy()
|
||||
old_succ = G.succ
|
||||
assert id(G.succ) == id(old_succ)
|
||||
old_adj = G.adj
|
||||
assert id(G.adj) == id(old_adj)
|
||||
|
||||
G._succ = {}
|
||||
assert id(G.succ) != id(old_succ)
|
||||
assert id(G.adj) != id(old_adj)
|
||||
|
||||
old_pred = G.pred
|
||||
assert id(G.pred) == id(old_pred)
|
||||
G._pred = {}
|
||||
assert id(G.pred) != id(old_pred)
|
||||
|
||||
def test_di_attributes_cached(self):
|
||||
G = self.K3.copy()
|
||||
assert id(G.in_edges) == id(G.in_edges)
|
||||
assert id(G.out_edges) == id(G.out_edges)
|
||||
assert id(G.in_degree) == id(G.in_degree)
|
||||
assert id(G.out_degree) == id(G.out_degree)
|
||||
assert id(G.succ) == id(G.succ)
|
||||
assert id(G.pred) == id(G.pred)
|
||||
|
||||
|
||||
class BaseAttrDiGraphTester(BaseDiGraphTester, BaseAttrGraphTester):
|
||||
def test_edges_data(self):
|
||||
G = self.K3
|
||||
all_edges = [
|
||||
(0, 1, {}),
|
||||
(0, 2, {}),
|
||||
(1, 0, {}),
|
||||
(1, 2, {}),
|
||||
(2, 0, {}),
|
||||
(2, 1, {}),
|
||||
]
|
||||
assert sorted(G.edges(data=True)) == all_edges
|
||||
assert sorted(G.edges(0, data=True)) == all_edges[:2]
|
||||
assert sorted(G.edges([0, 1], data=True)) == all_edges[:4]
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.edges(-1, True)
|
||||
|
||||
def test_in_degree_weighted(self):
|
||||
G = self.K3.copy()
|
||||
G.add_edge(0, 1, weight=0.3, other=1.2)
|
||||
assert sorted(G.in_degree(weight="weight")) == [(0, 2), (1, 1.3), (2, 2)]
|
||||
assert dict(G.in_degree(weight="weight")) == {0: 2, 1: 1.3, 2: 2}
|
||||
assert G.in_degree(1, weight="weight") == 1.3
|
||||
assert sorted(G.in_degree(weight="other")) == [(0, 2), (1, 2.2), (2, 2)]
|
||||
assert dict(G.in_degree(weight="other")) == {0: 2, 1: 2.2, 2: 2}
|
||||
assert G.in_degree(1, weight="other") == 2.2
|
||||
assert list(G.in_degree(iter([1]), weight="other")) == [(1, 2.2)]
|
||||
|
||||
def test_out_degree_weighted(self):
|
||||
G = self.K3.copy()
|
||||
G.add_edge(0, 1, weight=0.3, other=1.2)
|
||||
assert sorted(G.out_degree(weight="weight")) == [(0, 1.3), (1, 2), (2, 2)]
|
||||
assert dict(G.out_degree(weight="weight")) == {0: 1.3, 1: 2, 2: 2}
|
||||
assert G.out_degree(0, weight="weight") == 1.3
|
||||
assert sorted(G.out_degree(weight="other")) == [(0, 2.2), (1, 2), (2, 2)]
|
||||
assert dict(G.out_degree(weight="other")) == {0: 2.2, 1: 2, 2: 2}
|
||||
assert G.out_degree(0, weight="other") == 2.2
|
||||
assert list(G.out_degree(iter([0]), weight="other")) == [(0, 2.2)]
|
||||
|
||||
|
||||
class TestDiGraph(BaseAttrDiGraphTester, _TestGraph):
|
||||
"""Tests specific to dict-of-dict-of-dict digraph data structure"""
|
||||
|
||||
def setup_method(self):
|
||||
self.Graph = nx.DiGraph
|
||||
# build dict-of-dict-of-dict K3
|
||||
ed1, ed2, ed3, ed4, ed5, ed6 = ({}, {}, {}, {}, {}, {})
|
||||
self.k3adj = {0: {1: ed1, 2: ed2}, 1: {0: ed3, 2: ed4}, 2: {0: ed5, 1: ed6}}
|
||||
self.k3edges = [(0, 1), (0, 2), (1, 2)]
|
||||
self.k3nodes = [0, 1, 2]
|
||||
self.K3 = self.Graph()
|
||||
self.K3._succ = self.k3adj # K3._adj is synced with K3._succ
|
||||
self.K3._pred = {0: {1: ed3, 2: ed5}, 1: {0: ed1, 2: ed6}, 2: {0: ed2, 1: ed4}}
|
||||
self.K3._node = {}
|
||||
self.K3._node[0] = {}
|
||||
self.K3._node[1] = {}
|
||||
self.K3._node[2] = {}
|
||||
|
||||
ed1, ed2 = ({}, {})
|
||||
self.P3 = self.Graph()
|
||||
self.P3._succ = {0: {1: ed1}, 1: {2: ed2}, 2: {}}
|
||||
self.P3._pred = {0: {}, 1: {0: ed1}, 2: {1: ed2}}
|
||||
# P3._adj is synced with P3._succ
|
||||
self.P3._node = {}
|
||||
self.P3._node[0] = {}
|
||||
self.P3._node[1] = {}
|
||||
self.P3._node[2] = {}
|
||||
|
||||
def test_data_input(self):
|
||||
G = self.Graph({1: [2], 2: [1]}, name="test")
|
||||
assert G.name == "test"
|
||||
assert sorted(G.adj.items()) == [(1, {2: {}}), (2, {1: {}})]
|
||||
assert sorted(G.succ.items()) == [(1, {2: {}}), (2, {1: {}})]
|
||||
assert sorted(G.pred.items()) == [(1, {2: {}}), (2, {1: {}})]
|
||||
|
||||
def test_add_edge(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(0, 1)
|
||||
assert G.adj == {0: {1: {}}, 1: {}}
|
||||
assert G.succ == {0: {1: {}}, 1: {}}
|
||||
assert G.pred == {0: {}, 1: {0: {}}}
|
||||
G = self.Graph()
|
||||
G.add_edge(*(0, 1))
|
||||
assert G.adj == {0: {1: {}}, 1: {}}
|
||||
assert G.succ == {0: {1: {}}, 1: {}}
|
||||
assert G.pred == {0: {}, 1: {0: {}}}
|
||||
with pytest.raises(ValueError, match="None cannot be a node"):
|
||||
G.add_edge(None, 3)
|
||||
|
||||
def test_add_edges_from(self):
|
||||
G = self.Graph()
|
||||
G.add_edges_from([(0, 1), (0, 2, {"data": 3})], data=2)
|
||||
assert G.adj == {0: {1: {"data": 2}, 2: {"data": 3}}, 1: {}, 2: {}}
|
||||
assert G.succ == {0: {1: {"data": 2}, 2: {"data": 3}}, 1: {}, 2: {}}
|
||||
assert G.pred == {0: {}, 1: {0: {"data": 2}}, 2: {0: {"data": 3}}}
|
||||
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.add_edges_from([(0,)]) # too few in tuple
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.add_edges_from([(0, 1, 2, 3)]) # too many in tuple
|
||||
with pytest.raises(TypeError):
|
||||
G.add_edges_from([0]) # not a tuple
|
||||
with pytest.raises(ValueError, match="None cannot be a node"):
|
||||
G.add_edges_from([(None, 3), (3, 2)])
|
||||
|
||||
def test_remove_edge(self):
|
||||
G = self.K3.copy()
|
||||
G.remove_edge(0, 1)
|
||||
assert G.succ == {0: {2: {}}, 1: {0: {}, 2: {}}, 2: {0: {}, 1: {}}}
|
||||
assert G.pred == {0: {1: {}, 2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}}
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.remove_edge(-1, 0)
|
||||
|
||||
def test_remove_edges_from(self):
|
||||
G = self.K3.copy()
|
||||
G.remove_edges_from([(0, 1)])
|
||||
assert G.succ == {0: {2: {}}, 1: {0: {}, 2: {}}, 2: {0: {}, 1: {}}}
|
||||
assert G.pred == {0: {1: {}, 2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}}
|
||||
G.remove_edges_from([(0, 0)]) # silent fail
|
||||
|
||||
def test_clear(self):
|
||||
G = self.K3
|
||||
G.graph["name"] = "K3"
|
||||
G.clear()
|
||||
assert list(G.nodes) == []
|
||||
assert G.succ == {}
|
||||
assert G.pred == {}
|
||||
assert G.graph == {}
|
||||
|
||||
def test_clear_edges(self):
|
||||
G = self.K3
|
||||
G.graph["name"] = "K3"
|
||||
nodes = list(G.nodes)
|
||||
G.clear_edges()
|
||||
assert list(G.nodes) == nodes
|
||||
expected = {0: {}, 1: {}, 2: {}}
|
||||
assert G.succ == expected
|
||||
assert G.pred == expected
|
||||
assert list(G.edges) == []
|
||||
assert G.graph["name"] == "K3"
|
||||
|
||||
|
||||
class TestEdgeSubgraph(_TestGraphEdgeSubgraph):
|
||||
"""Unit tests for the :meth:`DiGraph.edge_subgraph` method."""
|
||||
|
||||
def setup_method(self):
|
||||
# Create a doubly-linked path graph on five nodes.
|
||||
G = nx.DiGraph(nx.path_graph(5))
|
||||
# Add some node, edge, and graph attributes.
|
||||
for i in range(5):
|
||||
G.nodes[i]["name"] = f"node{i}"
|
||||
G.edges[0, 1]["name"] = "edge01"
|
||||
G.edges[3, 4]["name"] = "edge34"
|
||||
G.graph["name"] = "graph"
|
||||
# Get the subgraph induced by the first and last edges.
|
||||
self.G = G
|
||||
self.H = G.edge_subgraph([(0, 1), (3, 4)])
|
||||
|
||||
def test_pred_succ(self):
|
||||
"""Test that nodes are added to predecessors and successors.
|
||||
|
||||
For more information, see GitHub issue #2370.
|
||||
|
||||
"""
|
||||
G = nx.DiGraph()
|
||||
G.add_edge(0, 1)
|
||||
H = G.edge_subgraph([(0, 1)])
|
||||
assert list(H.predecessors(0)) == []
|
||||
assert list(H.successors(0)) == [1]
|
||||
assert list(H.predecessors(1)) == [0]
|
||||
assert list(H.successors(1)) == []
|
||||
110
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_digraph_historical.py
vendored
Normal file
110
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_digraph_historical.py
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
"""Original NetworkX graph tests"""
|
||||
import pytest
|
||||
|
||||
import networkx
|
||||
import networkx as nx
|
||||
|
||||
from .historical_tests import HistoricalTests
|
||||
|
||||
|
||||
class TestDiGraphHistorical(HistoricalTests):
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
HistoricalTests.setup_class()
|
||||
cls.G = nx.DiGraph
|
||||
|
||||
def test_in_degree(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from("GJK")
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("B", "C"), ("C", "D")])
|
||||
|
||||
assert sorted(d for n, d in G.in_degree()) == [0, 0, 0, 0, 1, 2, 2]
|
||||
assert dict(G.in_degree()) == {
|
||||
"A": 0,
|
||||
"C": 2,
|
||||
"B": 1,
|
||||
"D": 2,
|
||||
"G": 0,
|
||||
"K": 0,
|
||||
"J": 0,
|
||||
}
|
||||
|
||||
def test_out_degree(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from("GJK")
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("B", "C"), ("C", "D")])
|
||||
assert sorted(v for k, v in G.in_degree()) == [0, 0, 0, 0, 1, 2, 2]
|
||||
assert dict(G.out_degree()) == {
|
||||
"A": 2,
|
||||
"C": 1,
|
||||
"B": 2,
|
||||
"D": 0,
|
||||
"G": 0,
|
||||
"K": 0,
|
||||
"J": 0,
|
||||
}
|
||||
|
||||
def test_degree_digraph(self):
|
||||
H = nx.DiGraph()
|
||||
H.add_edges_from([(1, 24), (1, 2)])
|
||||
assert sorted(d for n, d in H.in_degree([1, 24])) == [0, 1]
|
||||
assert sorted(d for n, d in H.out_degree([1, 24])) == [0, 2]
|
||||
assert sorted(d for n, d in H.degree([1, 24])) == [1, 2]
|
||||
|
||||
def test_neighbors(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from("GJK")
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("B", "C"), ("C", "D")])
|
||||
|
||||
assert sorted(G.neighbors("C")) == ["D"]
|
||||
assert sorted(G["C"]) == ["D"]
|
||||
assert sorted(G.neighbors("A")) == ["B", "C"]
|
||||
pytest.raises(nx.NetworkXError, G.neighbors, "j")
|
||||
pytest.raises(nx.NetworkXError, G.neighbors, "j")
|
||||
|
||||
def test_successors(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from("GJK")
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("B", "C"), ("C", "D")])
|
||||
assert sorted(G.successors("A")) == ["B", "C"]
|
||||
assert sorted(G.successors("A")) == ["B", "C"]
|
||||
assert sorted(G.successors("G")) == []
|
||||
assert sorted(G.successors("D")) == []
|
||||
assert sorted(G.successors("G")) == []
|
||||
pytest.raises(nx.NetworkXError, G.successors, "j")
|
||||
pytest.raises(nx.NetworkXError, G.successors, "j")
|
||||
|
||||
def test_predecessors(self):
|
||||
G = self.G()
|
||||
G.add_nodes_from("GJK")
|
||||
G.add_edges_from([("A", "B"), ("A", "C"), ("B", "D"), ("B", "C"), ("C", "D")])
|
||||
assert sorted(G.predecessors("C")) == ["A", "B"]
|
||||
assert sorted(G.predecessors("C")) == ["A", "B"]
|
||||
assert sorted(G.predecessors("G")) == []
|
||||
assert sorted(G.predecessors("A")) == []
|
||||
assert sorted(G.predecessors("G")) == []
|
||||
assert sorted(G.predecessors("A")) == []
|
||||
assert sorted(G.successors("D")) == []
|
||||
|
||||
pytest.raises(nx.NetworkXError, G.predecessors, "j")
|
||||
pytest.raises(nx.NetworkXError, G.predecessors, "j")
|
||||
|
||||
def test_reverse(self):
|
||||
G = nx.complete_graph(10)
|
||||
H = G.to_directed()
|
||||
HR = H.reverse()
|
||||
assert nx.is_isomorphic(H, HR)
|
||||
assert sorted(H.edges()) == sorted(HR.edges())
|
||||
|
||||
def test_reverse2(self):
|
||||
H = nx.DiGraph()
|
||||
foo = [H.add_edge(u, u + 1) for u in range(0, 5)]
|
||||
HR = H.reverse()
|
||||
for u in range(0, 5):
|
||||
assert HR.has_edge(u + 1, u)
|
||||
|
||||
def test_reverse3(self):
|
||||
H = nx.DiGraph()
|
||||
H.add_nodes_from([1, 2, 3, 4])
|
||||
HR = H.reverse()
|
||||
assert sorted(HR.nodes()) == [1, 2, 3, 4]
|
||||
177
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_filters.py
vendored
Normal file
177
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_filters.py
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
|
||||
|
||||
class TestFilterFactory:
|
||||
def test_no_filter(self):
|
||||
nf = nx.filters.no_filter
|
||||
assert nf()
|
||||
assert nf(1)
|
||||
assert nf(2, 1)
|
||||
|
||||
def test_hide_nodes(self):
|
||||
f = nx.classes.filters.hide_nodes([1, 2, 3])
|
||||
assert not f(1)
|
||||
assert not f(2)
|
||||
assert not f(3)
|
||||
assert f(4)
|
||||
assert f(0)
|
||||
assert f("a")
|
||||
pytest.raises(TypeError, f, 1, 2)
|
||||
pytest.raises(TypeError, f)
|
||||
|
||||
def test_show_nodes(self):
|
||||
f = nx.classes.filters.show_nodes([1, 2, 3])
|
||||
assert f(1)
|
||||
assert f(2)
|
||||
assert f(3)
|
||||
assert not f(4)
|
||||
assert not f(0)
|
||||
assert not f("a")
|
||||
pytest.raises(TypeError, f, 1, 2)
|
||||
pytest.raises(TypeError, f)
|
||||
|
||||
def test_hide_edges(self):
|
||||
factory = nx.classes.filters.hide_edges
|
||||
f = factory([(1, 2), (3, 4)])
|
||||
assert not f(1, 2)
|
||||
assert not f(3, 4)
|
||||
assert not f(4, 3)
|
||||
assert f(2, 3)
|
||||
assert f(0, -1)
|
||||
assert f("a", "b")
|
||||
pytest.raises(TypeError, f, 1, 2, 3)
|
||||
pytest.raises(TypeError, f, 1)
|
||||
pytest.raises(TypeError, f)
|
||||
pytest.raises(TypeError, factory, [1, 2, 3])
|
||||
pytest.raises(ValueError, factory, [(1, 2, 3)])
|
||||
|
||||
def test_show_edges(self):
|
||||
factory = nx.classes.filters.show_edges
|
||||
f = factory([(1, 2), (3, 4)])
|
||||
assert f(1, 2)
|
||||
assert f(3, 4)
|
||||
assert f(4, 3)
|
||||
assert not f(2, 3)
|
||||
assert not f(0, -1)
|
||||
assert not f("a", "b")
|
||||
pytest.raises(TypeError, f, 1, 2, 3)
|
||||
pytest.raises(TypeError, f, 1)
|
||||
pytest.raises(TypeError, f)
|
||||
pytest.raises(TypeError, factory, [1, 2, 3])
|
||||
pytest.raises(ValueError, factory, [(1, 2, 3)])
|
||||
|
||||
def test_hide_diedges(self):
|
||||
factory = nx.classes.filters.hide_diedges
|
||||
f = factory([(1, 2), (3, 4)])
|
||||
assert not f(1, 2)
|
||||
assert not f(3, 4)
|
||||
assert f(4, 3)
|
||||
assert f(2, 3)
|
||||
assert f(0, -1)
|
||||
assert f("a", "b")
|
||||
pytest.raises(TypeError, f, 1, 2, 3)
|
||||
pytest.raises(TypeError, f, 1)
|
||||
pytest.raises(TypeError, f)
|
||||
pytest.raises(TypeError, factory, [1, 2, 3])
|
||||
pytest.raises(ValueError, factory, [(1, 2, 3)])
|
||||
|
||||
def test_show_diedges(self):
|
||||
factory = nx.classes.filters.show_diedges
|
||||
f = factory([(1, 2), (3, 4)])
|
||||
assert f(1, 2)
|
||||
assert f(3, 4)
|
||||
assert not f(4, 3)
|
||||
assert not f(2, 3)
|
||||
assert not f(0, -1)
|
||||
assert not f("a", "b")
|
||||
pytest.raises(TypeError, f, 1, 2, 3)
|
||||
pytest.raises(TypeError, f, 1)
|
||||
pytest.raises(TypeError, f)
|
||||
pytest.raises(TypeError, factory, [1, 2, 3])
|
||||
pytest.raises(ValueError, factory, [(1, 2, 3)])
|
||||
|
||||
def test_hide_multiedges(self):
|
||||
factory = nx.classes.filters.hide_multiedges
|
||||
f = factory([(1, 2, 0), (3, 4, 1), (1, 2, 1)])
|
||||
assert not f(1, 2, 0)
|
||||
assert not f(1, 2, 1)
|
||||
assert f(1, 2, 2)
|
||||
assert f(3, 4, 0)
|
||||
assert not f(3, 4, 1)
|
||||
assert not f(4, 3, 1)
|
||||
assert f(4, 3, 0)
|
||||
assert f(2, 3, 0)
|
||||
assert f(0, -1, 0)
|
||||
assert f("a", "b", 0)
|
||||
pytest.raises(TypeError, f, 1, 2, 3, 4)
|
||||
pytest.raises(TypeError, f, 1, 2)
|
||||
pytest.raises(TypeError, f, 1)
|
||||
pytest.raises(TypeError, f)
|
||||
pytest.raises(TypeError, factory, [1, 2, 3])
|
||||
pytest.raises(ValueError, factory, [(1, 2)])
|
||||
pytest.raises(ValueError, factory, [(1, 2, 3, 4)])
|
||||
|
||||
def test_show_multiedges(self):
|
||||
factory = nx.classes.filters.show_multiedges
|
||||
f = factory([(1, 2, 0), (3, 4, 1), (1, 2, 1)])
|
||||
assert f(1, 2, 0)
|
||||
assert f(1, 2, 1)
|
||||
assert not f(1, 2, 2)
|
||||
assert not f(3, 4, 0)
|
||||
assert f(3, 4, 1)
|
||||
assert f(4, 3, 1)
|
||||
assert not f(4, 3, 0)
|
||||
assert not f(2, 3, 0)
|
||||
assert not f(0, -1, 0)
|
||||
assert not f("a", "b", 0)
|
||||
pytest.raises(TypeError, f, 1, 2, 3, 4)
|
||||
pytest.raises(TypeError, f, 1, 2)
|
||||
pytest.raises(TypeError, f, 1)
|
||||
pytest.raises(TypeError, f)
|
||||
pytest.raises(TypeError, factory, [1, 2, 3])
|
||||
pytest.raises(ValueError, factory, [(1, 2)])
|
||||
pytest.raises(ValueError, factory, [(1, 2, 3, 4)])
|
||||
|
||||
def test_hide_multidiedges(self):
|
||||
factory = nx.classes.filters.hide_multidiedges
|
||||
f = factory([(1, 2, 0), (3, 4, 1), (1, 2, 1)])
|
||||
assert not f(1, 2, 0)
|
||||
assert not f(1, 2, 1)
|
||||
assert f(1, 2, 2)
|
||||
assert f(3, 4, 0)
|
||||
assert not f(3, 4, 1)
|
||||
assert f(4, 3, 1)
|
||||
assert f(4, 3, 0)
|
||||
assert f(2, 3, 0)
|
||||
assert f(0, -1, 0)
|
||||
assert f("a", "b", 0)
|
||||
pytest.raises(TypeError, f, 1, 2, 3, 4)
|
||||
pytest.raises(TypeError, f, 1, 2)
|
||||
pytest.raises(TypeError, f, 1)
|
||||
pytest.raises(TypeError, f)
|
||||
pytest.raises(TypeError, factory, [1, 2, 3])
|
||||
pytest.raises(ValueError, factory, [(1, 2)])
|
||||
pytest.raises(ValueError, factory, [(1, 2, 3, 4)])
|
||||
|
||||
def test_show_multidiedges(self):
|
||||
factory = nx.classes.filters.show_multidiedges
|
||||
f = factory([(1, 2, 0), (3, 4, 1), (1, 2, 1)])
|
||||
assert f(1, 2, 0)
|
||||
assert f(1, 2, 1)
|
||||
assert not f(1, 2, 2)
|
||||
assert not f(3, 4, 0)
|
||||
assert f(3, 4, 1)
|
||||
assert not f(4, 3, 1)
|
||||
assert not f(4, 3, 0)
|
||||
assert not f(2, 3, 0)
|
||||
assert not f(0, -1, 0)
|
||||
assert not f("a", "b", 0)
|
||||
pytest.raises(TypeError, f, 1, 2, 3, 4)
|
||||
pytest.raises(TypeError, f, 1, 2)
|
||||
pytest.raises(TypeError, f, 1)
|
||||
pytest.raises(TypeError, f)
|
||||
pytest.raises(TypeError, factory, [1, 2, 3])
|
||||
pytest.raises(ValueError, factory, [(1, 2)])
|
||||
pytest.raises(ValueError, factory, [(1, 2, 3, 4)])
|
||||
782
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_function.py
vendored
Normal file
782
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_function.py
vendored
Normal file
@@ -0,0 +1,782 @@
|
||||
import random
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import edges_equal, nodes_equal
|
||||
|
||||
|
||||
class TestFunction:
|
||||
def setup_method(self):
|
||||
self.G = nx.Graph({0: [1, 2, 3], 1: [1, 2, 0], 4: []}, name="Test")
|
||||
self.Gdegree = {0: 3, 1: 2, 2: 2, 3: 1, 4: 0}
|
||||
self.Gnodes = list(range(5))
|
||||
self.Gedges = [(0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2)]
|
||||
self.DG = nx.DiGraph({0: [1, 2, 3], 1: [1, 2, 0], 4: []})
|
||||
self.DGin_degree = {0: 1, 1: 2, 2: 2, 3: 1, 4: 0}
|
||||
self.DGout_degree = {0: 3, 1: 3, 2: 0, 3: 0, 4: 0}
|
||||
self.DGnodes = list(range(5))
|
||||
self.DGedges = [(0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2)]
|
||||
|
||||
def test_nodes(self):
|
||||
assert nodes_equal(self.G.nodes(), list(nx.nodes(self.G)))
|
||||
assert nodes_equal(self.DG.nodes(), list(nx.nodes(self.DG)))
|
||||
|
||||
def test_edges(self):
|
||||
assert edges_equal(self.G.edges(), list(nx.edges(self.G)))
|
||||
assert sorted(self.DG.edges()) == sorted(nx.edges(self.DG))
|
||||
assert edges_equal(
|
||||
self.G.edges(nbunch=[0, 1, 3]), list(nx.edges(self.G, nbunch=[0, 1, 3]))
|
||||
)
|
||||
assert sorted(self.DG.edges(nbunch=[0, 1, 3])) == sorted(
|
||||
nx.edges(self.DG, nbunch=[0, 1, 3])
|
||||
)
|
||||
|
||||
def test_degree(self):
|
||||
assert edges_equal(self.G.degree(), list(nx.degree(self.G)))
|
||||
assert sorted(self.DG.degree()) == sorted(nx.degree(self.DG))
|
||||
assert edges_equal(
|
||||
self.G.degree(nbunch=[0, 1]), list(nx.degree(self.G, nbunch=[0, 1]))
|
||||
)
|
||||
assert sorted(self.DG.degree(nbunch=[0, 1])) == sorted(
|
||||
nx.degree(self.DG, nbunch=[0, 1])
|
||||
)
|
||||
assert edges_equal(
|
||||
self.G.degree(weight="weight"), list(nx.degree(self.G, weight="weight"))
|
||||
)
|
||||
assert sorted(self.DG.degree(weight="weight")) == sorted(
|
||||
nx.degree(self.DG, weight="weight")
|
||||
)
|
||||
|
||||
def test_neighbors(self):
|
||||
assert list(self.G.neighbors(1)) == list(nx.neighbors(self.G, 1))
|
||||
assert list(self.DG.neighbors(1)) == list(nx.neighbors(self.DG, 1))
|
||||
|
||||
def test_number_of_nodes(self):
|
||||
assert self.G.number_of_nodes() == nx.number_of_nodes(self.G)
|
||||
assert self.DG.number_of_nodes() == nx.number_of_nodes(self.DG)
|
||||
|
||||
def test_number_of_edges(self):
|
||||
assert self.G.number_of_edges() == nx.number_of_edges(self.G)
|
||||
assert self.DG.number_of_edges() == nx.number_of_edges(self.DG)
|
||||
|
||||
def test_is_directed(self):
|
||||
assert self.G.is_directed() == nx.is_directed(self.G)
|
||||
assert self.DG.is_directed() == nx.is_directed(self.DG)
|
||||
|
||||
def test_add_star(self):
|
||||
G = self.G.copy()
|
||||
nlist = [12, 13, 14, 15]
|
||||
nx.add_star(G, nlist)
|
||||
assert edges_equal(G.edges(nlist), [(12, 13), (12, 14), (12, 15)])
|
||||
|
||||
G = self.G.copy()
|
||||
nx.add_star(G, nlist, weight=2.0)
|
||||
assert edges_equal(
|
||||
G.edges(nlist, data=True),
|
||||
[
|
||||
(12, 13, {"weight": 2.0}),
|
||||
(12, 14, {"weight": 2.0}),
|
||||
(12, 15, {"weight": 2.0}),
|
||||
],
|
||||
)
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = [12]
|
||||
nx.add_star(G, nlist)
|
||||
assert nodes_equal(G, list(self.G) + nlist)
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = []
|
||||
nx.add_star(G, nlist)
|
||||
assert nodes_equal(G.nodes, self.Gnodes)
|
||||
assert edges_equal(G.edges, self.G.edges)
|
||||
|
||||
def test_add_path(self):
|
||||
G = self.G.copy()
|
||||
nlist = [12, 13, 14, 15]
|
||||
nx.add_path(G, nlist)
|
||||
assert edges_equal(G.edges(nlist), [(12, 13), (13, 14), (14, 15)])
|
||||
G = self.G.copy()
|
||||
nx.add_path(G, nlist, weight=2.0)
|
||||
assert edges_equal(
|
||||
G.edges(nlist, data=True),
|
||||
[
|
||||
(12, 13, {"weight": 2.0}),
|
||||
(13, 14, {"weight": 2.0}),
|
||||
(14, 15, {"weight": 2.0}),
|
||||
],
|
||||
)
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = ["node"]
|
||||
nx.add_path(G, nlist)
|
||||
assert edges_equal(G.edges(nlist), [])
|
||||
assert nodes_equal(G, list(self.G) + ["node"])
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = iter(["node"])
|
||||
nx.add_path(G, nlist)
|
||||
assert edges_equal(G.edges(["node"]), [])
|
||||
assert nodes_equal(G, list(self.G) + ["node"])
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = [12]
|
||||
nx.add_path(G, nlist)
|
||||
assert edges_equal(G.edges(nlist), [])
|
||||
assert nodes_equal(G, list(self.G) + [12])
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = iter([12])
|
||||
nx.add_path(G, nlist)
|
||||
assert edges_equal(G.edges([12]), [])
|
||||
assert nodes_equal(G, list(self.G) + [12])
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = []
|
||||
nx.add_path(G, nlist)
|
||||
assert edges_equal(G.edges, self.G.edges)
|
||||
assert nodes_equal(G, list(self.G))
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = iter([])
|
||||
nx.add_path(G, nlist)
|
||||
assert edges_equal(G.edges, self.G.edges)
|
||||
assert nodes_equal(G, list(self.G))
|
||||
|
||||
def test_add_cycle(self):
|
||||
G = self.G.copy()
|
||||
nlist = [12, 13, 14, 15]
|
||||
oklists = [
|
||||
[(12, 13), (12, 15), (13, 14), (14, 15)],
|
||||
[(12, 13), (13, 14), (14, 15), (15, 12)],
|
||||
]
|
||||
nx.add_cycle(G, nlist)
|
||||
assert sorted(G.edges(nlist)) in oklists
|
||||
G = self.G.copy()
|
||||
oklists = [
|
||||
[
|
||||
(12, 13, {"weight": 1.0}),
|
||||
(12, 15, {"weight": 1.0}),
|
||||
(13, 14, {"weight": 1.0}),
|
||||
(14, 15, {"weight": 1.0}),
|
||||
],
|
||||
[
|
||||
(12, 13, {"weight": 1.0}),
|
||||
(13, 14, {"weight": 1.0}),
|
||||
(14, 15, {"weight": 1.0}),
|
||||
(15, 12, {"weight": 1.0}),
|
||||
],
|
||||
]
|
||||
nx.add_cycle(G, nlist, weight=1.0)
|
||||
assert sorted(G.edges(nlist, data=True)) in oklists
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = [12]
|
||||
nx.add_cycle(G, nlist)
|
||||
assert nodes_equal(G, list(self.G) + nlist)
|
||||
|
||||
G = self.G.copy()
|
||||
nlist = []
|
||||
nx.add_cycle(G, nlist)
|
||||
assert nodes_equal(G.nodes, self.Gnodes)
|
||||
assert edges_equal(G.edges, self.G.edges)
|
||||
|
||||
def test_subgraph(self):
|
||||
assert (
|
||||
self.G.subgraph([0, 1, 2, 4]).adj == nx.subgraph(self.G, [0, 1, 2, 4]).adj
|
||||
)
|
||||
assert (
|
||||
self.DG.subgraph([0, 1, 2, 4]).adj == nx.subgraph(self.DG, [0, 1, 2, 4]).adj
|
||||
)
|
||||
assert (
|
||||
self.G.subgraph([0, 1, 2, 4]).adj
|
||||
== nx.induced_subgraph(self.G, [0, 1, 2, 4]).adj
|
||||
)
|
||||
assert (
|
||||
self.DG.subgraph([0, 1, 2, 4]).adj
|
||||
== nx.induced_subgraph(self.DG, [0, 1, 2, 4]).adj
|
||||
)
|
||||
# subgraph-subgraph chain is allowed in function interface
|
||||
H = nx.induced_subgraph(self.G.subgraph([0, 1, 2, 4]), [0, 1, 4])
|
||||
assert H._graph is not self.G
|
||||
assert H.adj == self.G.subgraph([0, 1, 4]).adj
|
||||
|
||||
def test_edge_subgraph(self):
|
||||
assert (
|
||||
self.G.edge_subgraph([(1, 2), (0, 3)]).adj
|
||||
== nx.edge_subgraph(self.G, [(1, 2), (0, 3)]).adj
|
||||
)
|
||||
assert (
|
||||
self.DG.edge_subgraph([(1, 2), (0, 3)]).adj
|
||||
== nx.edge_subgraph(self.DG, [(1, 2), (0, 3)]).adj
|
||||
)
|
||||
|
||||
def test_create_empty_copy(self):
|
||||
G = nx.create_empty_copy(self.G, with_data=False)
|
||||
assert nodes_equal(G, list(self.G))
|
||||
assert G.graph == {}
|
||||
assert G._node == {}.fromkeys(self.G.nodes(), {})
|
||||
assert G._adj == {}.fromkeys(self.G.nodes(), {})
|
||||
G = nx.create_empty_copy(self.G)
|
||||
assert nodes_equal(G, list(self.G))
|
||||
assert G.graph == self.G.graph
|
||||
assert G._node == self.G._node
|
||||
assert G._adj == {}.fromkeys(self.G.nodes(), {})
|
||||
|
||||
def test_degree_histogram(self):
|
||||
assert nx.degree_histogram(self.G) == [1, 1, 1, 1, 1]
|
||||
|
||||
def test_density(self):
|
||||
assert nx.density(self.G) == 0.5
|
||||
assert nx.density(self.DG) == 0.3
|
||||
G = nx.Graph()
|
||||
G.add_node(1)
|
||||
assert nx.density(G) == 0.0
|
||||
|
||||
def test_density_selfloop(self):
|
||||
G = nx.Graph()
|
||||
G.add_edge(1, 1)
|
||||
assert nx.density(G) == 0.0
|
||||
G.add_edge(1, 2)
|
||||
assert nx.density(G) == 2.0
|
||||
|
||||
def test_freeze(self):
|
||||
G = nx.freeze(self.G)
|
||||
assert G.frozen
|
||||
pytest.raises(nx.NetworkXError, G.add_node, 1)
|
||||
pytest.raises(nx.NetworkXError, G.add_nodes_from, [1])
|
||||
pytest.raises(nx.NetworkXError, G.remove_node, 1)
|
||||
pytest.raises(nx.NetworkXError, G.remove_nodes_from, [1])
|
||||
pytest.raises(nx.NetworkXError, G.add_edge, 1, 2)
|
||||
pytest.raises(nx.NetworkXError, G.add_edges_from, [(1, 2)])
|
||||
pytest.raises(nx.NetworkXError, G.remove_edge, 1, 2)
|
||||
pytest.raises(nx.NetworkXError, G.remove_edges_from, [(1, 2)])
|
||||
pytest.raises(nx.NetworkXError, G.clear_edges)
|
||||
pytest.raises(nx.NetworkXError, G.clear)
|
||||
|
||||
def test_is_frozen(self):
|
||||
assert not nx.is_frozen(self.G)
|
||||
G = nx.freeze(self.G)
|
||||
assert G.frozen == nx.is_frozen(self.G)
|
||||
assert G.frozen
|
||||
|
||||
def test_node_attributes_are_still_mutable_on_frozen_graph(self):
|
||||
G = nx.freeze(nx.path_graph(3))
|
||||
node = G.nodes[0]
|
||||
node["node_attribute"] = True
|
||||
assert node["node_attribute"] == True
|
||||
|
||||
def test_edge_attributes_are_still_mutable_on_frozen_graph(self):
|
||||
G = nx.freeze(nx.path_graph(3))
|
||||
edge = G.edges[(0, 1)]
|
||||
edge["edge_attribute"] = True
|
||||
assert edge["edge_attribute"] == True
|
||||
|
||||
def test_neighbors_complete_graph(self):
|
||||
graph = nx.complete_graph(100)
|
||||
pop = random.sample(list(graph), 1)
|
||||
nbors = list(nx.neighbors(graph, pop[0]))
|
||||
# should be all the other vertices in the graph
|
||||
assert len(nbors) == len(graph) - 1
|
||||
|
||||
graph = nx.path_graph(100)
|
||||
node = random.sample(list(graph), 1)[0]
|
||||
nbors = list(nx.neighbors(graph, node))
|
||||
# should be all the other vertices in the graph
|
||||
if node != 0 and node != 99:
|
||||
assert len(nbors) == 2
|
||||
else:
|
||||
assert len(nbors) == 1
|
||||
|
||||
# create a star graph with 99 outer nodes
|
||||
graph = nx.star_graph(99)
|
||||
nbors = list(nx.neighbors(graph, 0))
|
||||
assert len(nbors) == 99
|
||||
|
||||
def test_non_neighbors(self):
|
||||
graph = nx.complete_graph(100)
|
||||
pop = random.sample(list(graph), 1)
|
||||
nbors = list(nx.non_neighbors(graph, pop[0]))
|
||||
# should be all the other vertices in the graph
|
||||
assert len(nbors) == 0
|
||||
|
||||
graph = nx.path_graph(100)
|
||||
node = random.sample(list(graph), 1)[0]
|
||||
nbors = list(nx.non_neighbors(graph, node))
|
||||
# should be all the other vertices in the graph
|
||||
if node != 0 and node != 99:
|
||||
assert len(nbors) == 97
|
||||
else:
|
||||
assert len(nbors) == 98
|
||||
|
||||
# create a star graph with 99 outer nodes
|
||||
graph = nx.star_graph(99)
|
||||
nbors = list(nx.non_neighbors(graph, 0))
|
||||
assert len(nbors) == 0
|
||||
|
||||
# disconnected graph
|
||||
graph = nx.Graph()
|
||||
graph.add_nodes_from(range(10))
|
||||
nbors = list(nx.non_neighbors(graph, 0))
|
||||
assert len(nbors) == 9
|
||||
|
||||
def test_non_edges(self):
|
||||
# All possible edges exist
|
||||
graph = nx.complete_graph(5)
|
||||
nedges = list(nx.non_edges(graph))
|
||||
assert len(nedges) == 0
|
||||
|
||||
graph = nx.path_graph(4)
|
||||
expected = [(0, 2), (0, 3), (1, 3)]
|
||||
nedges = list(nx.non_edges(graph))
|
||||
for u, v in expected:
|
||||
assert (u, v) in nedges or (v, u) in nedges
|
||||
|
||||
graph = nx.star_graph(4)
|
||||
expected = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
|
||||
nedges = list(nx.non_edges(graph))
|
||||
for u, v in expected:
|
||||
assert (u, v) in nedges or (v, u) in nedges
|
||||
|
||||
# Directed graphs
|
||||
graph = nx.DiGraph()
|
||||
graph.add_edges_from([(0, 2), (2, 0), (2, 1)])
|
||||
expected = [(0, 1), (1, 0), (1, 2)]
|
||||
nedges = list(nx.non_edges(graph))
|
||||
for e in expected:
|
||||
assert e in nedges
|
||||
|
||||
def test_is_weighted(self):
|
||||
G = nx.Graph()
|
||||
assert not nx.is_weighted(G)
|
||||
|
||||
G = nx.path_graph(4)
|
||||
assert not nx.is_weighted(G)
|
||||
assert not nx.is_weighted(G, (2, 3))
|
||||
|
||||
G.add_node(4)
|
||||
G.add_edge(3, 4, weight=4)
|
||||
assert not nx.is_weighted(G)
|
||||
assert nx.is_weighted(G, (3, 4))
|
||||
|
||||
G = nx.DiGraph()
|
||||
G.add_weighted_edges_from(
|
||||
[
|
||||
("0", "3", 3),
|
||||
("0", "1", -5),
|
||||
("1", "0", -5),
|
||||
("0", "2", 2),
|
||||
("1", "2", 4),
|
||||
("2", "3", 1),
|
||||
]
|
||||
)
|
||||
assert nx.is_weighted(G)
|
||||
assert nx.is_weighted(G, ("1", "0"))
|
||||
|
||||
G = G.to_undirected()
|
||||
assert nx.is_weighted(G)
|
||||
assert nx.is_weighted(G, ("1", "0"))
|
||||
|
||||
pytest.raises(nx.NetworkXError, nx.is_weighted, G, (1, 2))
|
||||
|
||||
def test_is_negatively_weighted(self):
|
||||
G = nx.Graph()
|
||||
assert not nx.is_negatively_weighted(G)
|
||||
|
||||
G.add_node(1)
|
||||
G.add_nodes_from([2, 3, 4, 5])
|
||||
assert not nx.is_negatively_weighted(G)
|
||||
|
||||
G.add_edge(1, 2, weight=4)
|
||||
assert not nx.is_negatively_weighted(G, (1, 2))
|
||||
|
||||
G.add_edges_from([(1, 3), (2, 4), (2, 6)])
|
||||
G[1][3]["color"] = "blue"
|
||||
assert not nx.is_negatively_weighted(G)
|
||||
assert not nx.is_negatively_weighted(G, (1, 3))
|
||||
|
||||
G[2][4]["weight"] = -2
|
||||
assert nx.is_negatively_weighted(G, (2, 4))
|
||||
assert nx.is_negatively_weighted(G)
|
||||
|
||||
G = nx.DiGraph()
|
||||
G.add_weighted_edges_from(
|
||||
[
|
||||
("0", "3", 3),
|
||||
("0", "1", -5),
|
||||
("1", "0", -2),
|
||||
("0", "2", 2),
|
||||
("1", "2", -3),
|
||||
("2", "3", 1),
|
||||
]
|
||||
)
|
||||
assert nx.is_negatively_weighted(G)
|
||||
assert not nx.is_negatively_weighted(G, ("0", "3"))
|
||||
assert nx.is_negatively_weighted(G, ("1", "0"))
|
||||
|
||||
pytest.raises(nx.NetworkXError, nx.is_negatively_weighted, G, (1, 4))
|
||||
|
||||
|
||||
class TestCommonNeighbors:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.func = staticmethod(nx.common_neighbors)
|
||||
|
||||
def test_func(G, u, v, expected):
|
||||
result = sorted(cls.func(G, u, v))
|
||||
assert result == expected
|
||||
|
||||
cls.test = staticmethod(test_func)
|
||||
|
||||
def test_K5(self):
|
||||
G = nx.complete_graph(5)
|
||||
self.test(G, 0, 1, [2, 3, 4])
|
||||
|
||||
def test_P3(self):
|
||||
G = nx.path_graph(3)
|
||||
self.test(G, 0, 2, [1])
|
||||
|
||||
def test_S4(self):
|
||||
G = nx.star_graph(4)
|
||||
self.test(G, 1, 2, [0])
|
||||
|
||||
def test_digraph(self):
|
||||
with pytest.raises(nx.NetworkXNotImplemented):
|
||||
G = nx.DiGraph()
|
||||
G.add_edges_from([(0, 1), (1, 2)])
|
||||
self.func(G, 0, 2)
|
||||
|
||||
def test_nonexistent_nodes(self):
|
||||
G = nx.complete_graph(5)
|
||||
pytest.raises(nx.NetworkXError, nx.common_neighbors, G, 5, 4)
|
||||
pytest.raises(nx.NetworkXError, nx.common_neighbors, G, 4, 5)
|
||||
pytest.raises(nx.NetworkXError, nx.common_neighbors, G, 5, 6)
|
||||
|
||||
def test_custom1(self):
|
||||
"""Case of no common neighbors."""
|
||||
G = nx.Graph()
|
||||
G.add_nodes_from([0, 1])
|
||||
self.test(G, 0, 1, [])
|
||||
|
||||
def test_custom2(self):
|
||||
"""Case of equal nodes."""
|
||||
G = nx.complete_graph(4)
|
||||
self.test(G, 0, 0, [1, 2, 3])
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"graph_type", (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)
|
||||
)
|
||||
def test_set_node_attributes(graph_type):
|
||||
# Test single value
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
vals = 100
|
||||
attr = "hello"
|
||||
nx.set_node_attributes(G, vals, attr)
|
||||
assert G.nodes[0][attr] == vals
|
||||
assert G.nodes[1][attr] == vals
|
||||
assert G.nodes[2][attr] == vals
|
||||
|
||||
# Test dictionary
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
vals = dict(zip(sorted(G.nodes()), range(len(G))))
|
||||
attr = "hi"
|
||||
nx.set_node_attributes(G, vals, attr)
|
||||
assert G.nodes[0][attr] == 0
|
||||
assert G.nodes[1][attr] == 1
|
||||
assert G.nodes[2][attr] == 2
|
||||
|
||||
# Test dictionary of dictionaries
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
d = {"hi": 0, "hello": 200}
|
||||
vals = dict.fromkeys(G.nodes(), d)
|
||||
vals.pop(0)
|
||||
nx.set_node_attributes(G, vals)
|
||||
assert G.nodes[0] == {}
|
||||
assert G.nodes[1]["hi"] == 0
|
||||
assert G.nodes[2]["hello"] == 200
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("values", "name"),
|
||||
(
|
||||
({0: "red", 1: "blue"}, "color"), # values dictionary
|
||||
({0: {"color": "red"}, 1: {"color": "blue"}}, None), # dict-of-dict
|
||||
),
|
||||
)
|
||||
def test_set_node_attributes_ignores_extra_nodes(values, name):
|
||||
"""
|
||||
When `values` is a dict or dict-of-dict keyed by nodes, ensure that keys
|
||||
that correspond to nodes not in G are ignored.
|
||||
"""
|
||||
G = nx.Graph()
|
||||
G.add_node(0)
|
||||
nx.set_node_attributes(G, values, name)
|
||||
assert G.nodes[0]["color"] == "red"
|
||||
assert 1 not in G.nodes
|
||||
|
||||
|
||||
@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph))
|
||||
def test_set_edge_attributes(graph_type):
|
||||
# Test single value
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
attr = "hello"
|
||||
vals = 3
|
||||
nx.set_edge_attributes(G, vals, attr)
|
||||
assert G[0][1][attr] == vals
|
||||
assert G[1][2][attr] == vals
|
||||
|
||||
# Test multiple values
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
attr = "hi"
|
||||
edges = [(0, 1), (1, 2)]
|
||||
vals = dict(zip(edges, range(len(edges))))
|
||||
nx.set_edge_attributes(G, vals, attr)
|
||||
assert G[0][1][attr] == 0
|
||||
assert G[1][2][attr] == 1
|
||||
|
||||
# Test dictionary of dictionaries
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
d = {"hi": 0, "hello": 200}
|
||||
edges = [(0, 1)]
|
||||
vals = dict.fromkeys(edges, d)
|
||||
nx.set_edge_attributes(G, vals)
|
||||
assert G[0][1]["hi"] == 0
|
||||
assert G[0][1]["hello"] == 200
|
||||
assert G[1][2] == {}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("values", "name"),
|
||||
(
|
||||
({(0, 1): 1.0, (0, 2): 2.0}, "weight"), # values dict
|
||||
({(0, 1): {"weight": 1.0}, (0, 2): {"weight": 2.0}}, None), # values dod
|
||||
),
|
||||
)
|
||||
def test_set_edge_attributes_ignores_extra_edges(values, name):
|
||||
"""If `values` is a dict or dict-of-dicts containing edges that are not in
|
||||
G, data associate with these edges should be ignored.
|
||||
"""
|
||||
G = nx.Graph([(0, 1)])
|
||||
nx.set_edge_attributes(G, values, name)
|
||||
assert G[0][1]["weight"] == 1.0
|
||||
assert (0, 2) not in G.edges
|
||||
|
||||
|
||||
@pytest.mark.parametrize("graph_type", (nx.MultiGraph, nx.MultiDiGraph))
|
||||
def test_set_edge_attributes_multi(graph_type):
|
||||
# Test single value
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
attr = "hello"
|
||||
vals = 3
|
||||
nx.set_edge_attributes(G, vals, attr)
|
||||
assert G[0][1][0][attr] == vals
|
||||
assert G[1][2][0][attr] == vals
|
||||
|
||||
# Test multiple values
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
attr = "hi"
|
||||
edges = [(0, 1, 0), (1, 2, 0)]
|
||||
vals = dict(zip(edges, range(len(edges))))
|
||||
nx.set_edge_attributes(G, vals, attr)
|
||||
assert G[0][1][0][attr] == 0
|
||||
assert G[1][2][0][attr] == 1
|
||||
|
||||
# Test dictionary of dictionaries
|
||||
G = nx.path_graph(3, create_using=graph_type)
|
||||
d = {"hi": 0, "hello": 200}
|
||||
edges = [(0, 1, 0)]
|
||||
vals = dict.fromkeys(edges, d)
|
||||
nx.set_edge_attributes(G, vals)
|
||||
assert G[0][1][0]["hi"] == 0
|
||||
assert G[0][1][0]["hello"] == 200
|
||||
assert G[1][2][0] == {}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("values", "name"),
|
||||
(
|
||||
({(0, 1, 0): 1.0, (0, 2, 0): 2.0}, "weight"), # values dict
|
||||
({(0, 1, 0): {"weight": 1.0}, (0, 2, 0): {"weight": 2.0}}, None), # values dod
|
||||
),
|
||||
)
|
||||
def test_set_edge_attributes_multi_ignores_extra_edges(values, name):
|
||||
"""If `values` is a dict or dict-of-dicts containing edges that are not in
|
||||
G, data associate with these edges should be ignored.
|
||||
"""
|
||||
G = nx.MultiGraph([(0, 1, 0), (0, 1, 1)])
|
||||
nx.set_edge_attributes(G, values, name)
|
||||
assert G[0][1][0]["weight"] == 1.0
|
||||
assert G[0][1][1] == {}
|
||||
assert (0, 2) not in G.edges()
|
||||
|
||||
|
||||
def test_get_node_attributes():
|
||||
graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()]
|
||||
for G in graphs:
|
||||
G = nx.path_graph(3, create_using=G)
|
||||
attr = "hello"
|
||||
vals = 100
|
||||
nx.set_node_attributes(G, vals, attr)
|
||||
attrs = nx.get_node_attributes(G, attr)
|
||||
assert attrs[0] == vals
|
||||
assert attrs[1] == vals
|
||||
assert attrs[2] == vals
|
||||
|
||||
|
||||
def test_get_edge_attributes():
|
||||
graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()]
|
||||
for G in graphs:
|
||||
G = nx.path_graph(3, create_using=G)
|
||||
attr = "hello"
|
||||
vals = 100
|
||||
nx.set_edge_attributes(G, vals, attr)
|
||||
attrs = nx.get_edge_attributes(G, attr)
|
||||
|
||||
assert len(attrs) == 2
|
||||
if G.is_multigraph():
|
||||
keys = [(0, 1, 0), (1, 2, 0)]
|
||||
for u, v, k in keys:
|
||||
try:
|
||||
assert attrs[(u, v, k)] == 100
|
||||
except KeyError:
|
||||
assert attrs[(v, u, k)] == 100
|
||||
else:
|
||||
keys = [(0, 1), (1, 2)]
|
||||
for u, v in keys:
|
||||
try:
|
||||
assert attrs[(u, v)] == 100
|
||||
except KeyError:
|
||||
assert attrs[(v, u)] == 100
|
||||
|
||||
|
||||
def test_is_empty():
|
||||
graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()]
|
||||
for G in graphs:
|
||||
assert nx.is_empty(G)
|
||||
G.add_nodes_from(range(5))
|
||||
assert nx.is_empty(G)
|
||||
G.add_edges_from([(1, 2), (3, 4)])
|
||||
assert not nx.is_empty(G)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"graph_type", [nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph]
|
||||
)
|
||||
def test_selfloops(graph_type):
|
||||
G = nx.complete_graph(3, create_using=graph_type)
|
||||
G.add_edge(0, 0)
|
||||
assert nodes_equal(nx.nodes_with_selfloops(G), [0])
|
||||
assert edges_equal(nx.selfloop_edges(G), [(0, 0)])
|
||||
assert edges_equal(nx.selfloop_edges(G, data=True), [(0, 0, {})])
|
||||
assert nx.number_of_selfloops(G) == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"graph_type", [nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph]
|
||||
)
|
||||
def test_selfloop_edges_attr(graph_type):
|
||||
G = nx.complete_graph(3, create_using=graph_type)
|
||||
G.add_edge(0, 0)
|
||||
G.add_edge(1, 1, weight=2)
|
||||
assert edges_equal(
|
||||
nx.selfloop_edges(G, data=True), [(0, 0, {}), (1, 1, {"weight": 2})]
|
||||
)
|
||||
assert edges_equal(nx.selfloop_edges(G, data="weight"), [(0, 0, None), (1, 1, 2)])
|
||||
|
||||
|
||||
def test_selfloop_edges_multi_with_data_and_keys():
|
||||
G = nx.complete_graph(3, create_using=nx.MultiGraph)
|
||||
G.add_edge(0, 0, weight=10)
|
||||
G.add_edge(0, 0, weight=100)
|
||||
assert edges_equal(
|
||||
nx.selfloop_edges(G, data="weight", keys=True), [(0, 0, 0, 10), (0, 0, 1, 100)]
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("graph_type", [nx.Graph, nx.DiGraph])
|
||||
def test_selfloops_removal(graph_type):
|
||||
G = nx.complete_graph(3, create_using=graph_type)
|
||||
G.add_edge(0, 0)
|
||||
G.remove_edges_from(nx.selfloop_edges(G, keys=True))
|
||||
G.add_edge(0, 0)
|
||||
G.remove_edges_from(nx.selfloop_edges(G, data=True))
|
||||
G.add_edge(0, 0)
|
||||
G.remove_edges_from(nx.selfloop_edges(G, keys=True, data=True))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("graph_type", [nx.MultiGraph, nx.MultiDiGraph])
|
||||
def test_selfloops_removal_multi(graph_type):
|
||||
"""test removing selfloops behavior vis-a-vis altering a dict while iterating.
|
||||
cf. gh-4068"""
|
||||
G = nx.complete_graph(3, create_using=graph_type)
|
||||
# Defaults - see gh-4080
|
||||
G.add_edge(0, 0)
|
||||
G.add_edge(0, 0)
|
||||
G.remove_edges_from(nx.selfloop_edges(G))
|
||||
assert (0, 0) not in G.edges()
|
||||
# With keys
|
||||
G.add_edge(0, 0)
|
||||
G.add_edge(0, 0)
|
||||
with pytest.raises(RuntimeError):
|
||||
G.remove_edges_from(nx.selfloop_edges(G, keys=True))
|
||||
# With data
|
||||
G.add_edge(0, 0)
|
||||
G.add_edge(0, 0)
|
||||
with pytest.raises(TypeError):
|
||||
G.remove_edges_from(nx.selfloop_edges(G, data=True))
|
||||
# With keys and data
|
||||
G.add_edge(0, 0)
|
||||
G.add_edge(0, 0)
|
||||
with pytest.raises(RuntimeError):
|
||||
G.remove_edges_from(nx.selfloop_edges(G, data=True, keys=True))
|
||||
|
||||
|
||||
def test_pathweight():
|
||||
valid_path = [1, 2, 3]
|
||||
invalid_path = [1, 3, 2]
|
||||
graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()]
|
||||
edges = [
|
||||
(1, 2, {"cost": 5, "dist": 6}),
|
||||
(2, 3, {"cost": 3, "dist": 4}),
|
||||
(1, 2, {"cost": 1, "dist": 2}),
|
||||
]
|
||||
for graph in graphs:
|
||||
graph.add_edges_from(edges)
|
||||
assert nx.path_weight(graph, valid_path, "cost") == 4
|
||||
assert nx.path_weight(graph, valid_path, "dist") == 6
|
||||
pytest.raises(nx.NetworkXNoPath, nx.path_weight, graph, invalid_path, "cost")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"G", (nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph())
|
||||
)
|
||||
def test_ispath(G):
|
||||
G.add_edges_from([(1, 2), (2, 3), (1, 2), (3, 4)])
|
||||
valid_path = [1, 2, 3, 4]
|
||||
invalid_path = [1, 2, 4, 3] # wrong node order
|
||||
another_invalid_path = [1, 2, 3, 4, 5] # contains node not in G
|
||||
assert nx.is_path(G, valid_path)
|
||||
assert not nx.is_path(G, invalid_path)
|
||||
assert not nx.is_path(G, another_invalid_path)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("G", (nx.Graph(), nx.DiGraph()))
|
||||
def test_restricted_view(G):
|
||||
G.add_edges_from([(0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2)])
|
||||
G.add_node(4)
|
||||
H = nx.restricted_view(G, [0, 2, 5], [(1, 2), (3, 4)])
|
||||
assert set(H.nodes()) == {1, 3, 4}
|
||||
assert set(H.edges()) == {(1, 1)}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("G", (nx.MultiGraph(), nx.MultiDiGraph()))
|
||||
def test_restricted_view_multi(G):
|
||||
G.add_edges_from(
|
||||
[(0, 1, 0), (0, 2, 0), (0, 3, 0), (0, 1, 1), (1, 0, 0), (1, 1, 0), (1, 2, 0)]
|
||||
)
|
||||
G.add_node(4)
|
||||
H = nx.restricted_view(G, [0, 2, 5], [(1, 2, 0), (3, 4, 0)])
|
||||
assert set(H.nodes()) == {1, 3, 4}
|
||||
assert set(H.edges()) == {(1, 1)}
|
||||
920
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_graph.py
vendored
Normal file
920
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_graph.py
vendored
Normal file
@@ -0,0 +1,920 @@
|
||||
import gc
|
||||
import pickle
|
||||
import platform
|
||||
import weakref
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import edges_equal, graphs_equal, nodes_equal
|
||||
|
||||
|
||||
class BaseGraphTester:
|
||||
"""Tests for data-structure independent graph class features."""
|
||||
|
||||
def test_contains(self):
|
||||
G = self.K3
|
||||
assert 1 in G
|
||||
assert 4 not in G
|
||||
assert "b" not in G
|
||||
assert [] not in G # no exception for nonhashable
|
||||
assert {1: 1} not in G # no exception for nonhashable
|
||||
|
||||
def test_order(self):
|
||||
G = self.K3
|
||||
assert len(G) == 3
|
||||
assert G.order() == 3
|
||||
assert G.number_of_nodes() == 3
|
||||
|
||||
def test_nodes(self):
|
||||
G = self.K3
|
||||
assert isinstance(G._node, G.node_dict_factory)
|
||||
assert isinstance(G._adj, G.adjlist_outer_dict_factory)
|
||||
assert all(
|
||||
isinstance(adj, G.adjlist_inner_dict_factory) for adj in G._adj.values()
|
||||
)
|
||||
assert sorted(G.nodes()) == self.k3nodes
|
||||
assert sorted(G.nodes(data=True)) == [(0, {}), (1, {}), (2, {})]
|
||||
|
||||
def test_none_node(self):
|
||||
G = self.Graph()
|
||||
with pytest.raises(ValueError):
|
||||
G.add_node(None)
|
||||
with pytest.raises(ValueError):
|
||||
G.add_nodes_from([None])
|
||||
with pytest.raises(ValueError):
|
||||
G.add_edge(0, None)
|
||||
with pytest.raises(ValueError):
|
||||
G.add_edges_from([(0, None)])
|
||||
|
||||
def test_has_node(self):
|
||||
G = self.K3
|
||||
assert G.has_node(1)
|
||||
assert not G.has_node(4)
|
||||
assert not G.has_node([]) # no exception for nonhashable
|
||||
assert not G.has_node({1: 1}) # no exception for nonhashable
|
||||
|
||||
def test_has_edge(self):
|
||||
G = self.K3
|
||||
assert G.has_edge(0, 1)
|
||||
assert not G.has_edge(0, -1)
|
||||
|
||||
def test_neighbors(self):
|
||||
G = self.K3
|
||||
assert sorted(G.neighbors(0)) == [1, 2]
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.neighbors(-1)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
platform.python_implementation() == "PyPy", reason="PyPy gc is different"
|
||||
)
|
||||
def test_memory_leak(self):
|
||||
G = self.Graph()
|
||||
|
||||
def count_objects_of_type(_type):
|
||||
# Iterating over all objects tracked by gc can include weak references
|
||||
# whose weakly-referenced objects may no longer exist. Calling `isinstance`
|
||||
# on such a weak reference will raise ReferenceError. There are at least
|
||||
# three workarounds for this: one is to compare type names instead of using
|
||||
# `isinstance` such as `type(obj).__name__ == typename`, another is to use
|
||||
# `type(obj) == _type`, and the last is to ignore ProxyTypes as we do below.
|
||||
# NOTE: even if this safeguard is deemed unnecessary to pass NetworkX tests,
|
||||
# we should still keep it for maximum safety for other NetworkX backends.
|
||||
return sum(
|
||||
1
|
||||
for obj in gc.get_objects()
|
||||
if not isinstance(obj, weakref.ProxyTypes) and isinstance(obj, _type)
|
||||
)
|
||||
|
||||
gc.collect()
|
||||
before = count_objects_of_type(self.Graph)
|
||||
G.copy()
|
||||
gc.collect()
|
||||
after = count_objects_of_type(self.Graph)
|
||||
assert before == after
|
||||
|
||||
# test a subgraph of the base class
|
||||
class MyGraph(self.Graph):
|
||||
pass
|
||||
|
||||
gc.collect()
|
||||
G = MyGraph()
|
||||
before = count_objects_of_type(MyGraph)
|
||||
G.copy()
|
||||
gc.collect()
|
||||
after = count_objects_of_type(MyGraph)
|
||||
assert before == after
|
||||
|
||||
def test_edges(self):
|
||||
G = self.K3
|
||||
assert isinstance(G._adj, G.adjlist_outer_dict_factory)
|
||||
assert edges_equal(G.edges(), [(0, 1), (0, 2), (1, 2)])
|
||||
assert edges_equal(G.edges(0), [(0, 1), (0, 2)])
|
||||
assert edges_equal(G.edges([0, 1]), [(0, 1), (0, 2), (1, 2)])
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.edges(-1)
|
||||
|
||||
def test_degree(self):
|
||||
G = self.K3
|
||||
assert sorted(G.degree()) == [(0, 2), (1, 2), (2, 2)]
|
||||
assert dict(G.degree()) == {0: 2, 1: 2, 2: 2}
|
||||
assert G.degree(0) == 2
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.degree(-1) # node not in graph
|
||||
|
||||
def test_size(self):
|
||||
G = self.K3
|
||||
assert G.size() == 3
|
||||
assert G.number_of_edges() == 3
|
||||
|
||||
def test_nbunch_iter(self):
|
||||
G = self.K3
|
||||
assert nodes_equal(G.nbunch_iter(), self.k3nodes) # all nodes
|
||||
assert nodes_equal(G.nbunch_iter(0), [0]) # single node
|
||||
assert nodes_equal(G.nbunch_iter([0, 1]), [0, 1]) # sequence
|
||||
# sequence with none in graph
|
||||
assert nodes_equal(G.nbunch_iter([-1]), [])
|
||||
# string sequence with none in graph
|
||||
assert nodes_equal(G.nbunch_iter("foo"), [])
|
||||
# node not in graph doesn't get caught upon creation of iterator
|
||||
bunch = G.nbunch_iter(-1)
|
||||
# but gets caught when iterator used
|
||||
with pytest.raises(nx.NetworkXError, match="is not a node or a sequence"):
|
||||
list(bunch)
|
||||
# unhashable doesn't get caught upon creation of iterator
|
||||
bunch = G.nbunch_iter([0, 1, 2, {}])
|
||||
# but gets caught when iterator hits the unhashable
|
||||
with pytest.raises(
|
||||
nx.NetworkXError, match="in sequence nbunch is not a valid node"
|
||||
):
|
||||
list(bunch)
|
||||
|
||||
def test_nbunch_iter_node_format_raise(self):
|
||||
# Tests that a node that would have failed string formatting
|
||||
# doesn't cause an error when attempting to raise a
|
||||
# :exc:`nx.NetworkXError`.
|
||||
|
||||
# For more information, see pull request #1813.
|
||||
G = self.Graph()
|
||||
nbunch = [("x", set())]
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
list(G.nbunch_iter(nbunch))
|
||||
|
||||
def test_selfloop_degree(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 1)
|
||||
assert sorted(G.degree()) == [(1, 2)]
|
||||
assert dict(G.degree()) == {1: 2}
|
||||
assert G.degree(1) == 2
|
||||
assert sorted(G.degree([1])) == [(1, 2)]
|
||||
assert G.degree(1, weight="weight") == 2
|
||||
|
||||
def test_selfloops(self):
|
||||
G = self.K3.copy()
|
||||
G.add_edge(0, 0)
|
||||
assert nodes_equal(nx.nodes_with_selfloops(G), [0])
|
||||
assert edges_equal(nx.selfloop_edges(G), [(0, 0)])
|
||||
assert nx.number_of_selfloops(G) == 1
|
||||
G.remove_edge(0, 0)
|
||||
G.add_edge(0, 0)
|
||||
G.remove_edges_from([(0, 0)])
|
||||
G.add_edge(1, 1)
|
||||
G.remove_node(1)
|
||||
G.add_edge(0, 0)
|
||||
G.add_edge(1, 1)
|
||||
G.remove_nodes_from([0, 1])
|
||||
|
||||
def test_cache_reset(self):
|
||||
G = self.K3.copy()
|
||||
old_adj = G.adj
|
||||
assert id(G.adj) == id(old_adj)
|
||||
G._adj = {}
|
||||
assert id(G.adj) != id(old_adj)
|
||||
|
||||
old_nodes = G.nodes
|
||||
assert id(G.nodes) == id(old_nodes)
|
||||
G._node = {}
|
||||
assert id(G.nodes) != id(old_nodes)
|
||||
|
||||
def test_attributes_cached(self):
|
||||
G = self.K3.copy()
|
||||
assert id(G.nodes) == id(G.nodes)
|
||||
assert id(G.edges) == id(G.edges)
|
||||
assert id(G.degree) == id(G.degree)
|
||||
assert id(G.adj) == id(G.adj)
|
||||
|
||||
|
||||
class BaseAttrGraphTester(BaseGraphTester):
|
||||
"""Tests of graph class attribute features."""
|
||||
|
||||
def test_weighted_degree(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 2, weight=2, other=3)
|
||||
G.add_edge(2, 3, weight=3, other=4)
|
||||
assert sorted(d for n, d in G.degree(weight="weight")) == [2, 3, 5]
|
||||
assert dict(G.degree(weight="weight")) == {1: 2, 2: 5, 3: 3}
|
||||
assert G.degree(1, weight="weight") == 2
|
||||
assert nodes_equal((G.degree([1], weight="weight")), [(1, 2)])
|
||||
|
||||
assert nodes_equal((d for n, d in G.degree(weight="other")), [3, 7, 4])
|
||||
assert dict(G.degree(weight="other")) == {1: 3, 2: 7, 3: 4}
|
||||
assert G.degree(1, weight="other") == 3
|
||||
assert edges_equal((G.degree([1], weight="other")), [(1, 3)])
|
||||
|
||||
def add_attributes(self, G):
|
||||
G.graph["foo"] = []
|
||||
G.nodes[0]["foo"] = []
|
||||
G.remove_edge(1, 2)
|
||||
ll = []
|
||||
G.add_edge(1, 2, foo=ll)
|
||||
G.add_edge(2, 1, foo=ll)
|
||||
|
||||
def test_name(self):
|
||||
G = self.Graph(name="")
|
||||
assert G.name == ""
|
||||
G = self.Graph(name="test")
|
||||
assert G.name == "test"
|
||||
|
||||
def test_str_unnamed(self):
|
||||
G = self.Graph()
|
||||
G.add_edges_from([(1, 2), (2, 3)])
|
||||
assert str(G) == f"{type(G).__name__} with 3 nodes and 2 edges"
|
||||
|
||||
def test_str_named(self):
|
||||
G = self.Graph(name="foo")
|
||||
G.add_edges_from([(1, 2), (2, 3)])
|
||||
assert str(G) == f"{type(G).__name__} named 'foo' with 3 nodes and 2 edges"
|
||||
|
||||
def test_graph_chain(self):
|
||||
G = self.Graph([(0, 1), (1, 2)])
|
||||
DG = G.to_directed(as_view=True)
|
||||
SDG = DG.subgraph([0, 1])
|
||||
RSDG = SDG.reverse(copy=False)
|
||||
assert G is DG._graph
|
||||
assert DG is SDG._graph
|
||||
assert SDG is RSDG._graph
|
||||
|
||||
def test_copy(self):
|
||||
G = self.Graph()
|
||||
G.add_node(0)
|
||||
G.add_edge(1, 2)
|
||||
self.add_attributes(G)
|
||||
# copy edge datadict but any container attr are same
|
||||
H = G.copy()
|
||||
self.graphs_equal(H, G)
|
||||
self.different_attrdict(H, G)
|
||||
self.shallow_copy_attrdict(H, G)
|
||||
|
||||
def test_class_copy(self):
|
||||
G = self.Graph()
|
||||
G.add_node(0)
|
||||
G.add_edge(1, 2)
|
||||
self.add_attributes(G)
|
||||
# copy edge datadict but any container attr are same
|
||||
H = G.__class__(G)
|
||||
self.graphs_equal(H, G)
|
||||
self.different_attrdict(H, G)
|
||||
self.shallow_copy_attrdict(H, G)
|
||||
|
||||
def test_fresh_copy(self):
|
||||
G = self.Graph()
|
||||
G.add_node(0)
|
||||
G.add_edge(1, 2)
|
||||
self.add_attributes(G)
|
||||
# copy graph structure but use fresh datadict
|
||||
H = G.__class__()
|
||||
H.add_nodes_from(G)
|
||||
H.add_edges_from(G.edges())
|
||||
assert len(G.nodes[0]) == 1
|
||||
ddict = G.adj[1][2][0] if G.is_multigraph() else G.adj[1][2]
|
||||
assert len(ddict) == 1
|
||||
assert len(H.nodes[0]) == 0
|
||||
ddict = H.adj[1][2][0] if H.is_multigraph() else H.adj[1][2]
|
||||
assert len(ddict) == 0
|
||||
|
||||
def is_deepcopy(self, H, G):
|
||||
self.graphs_equal(H, G)
|
||||
self.different_attrdict(H, G)
|
||||
self.deep_copy_attrdict(H, G)
|
||||
|
||||
def deep_copy_attrdict(self, H, G):
|
||||
self.deepcopy_graph_attr(H, G)
|
||||
self.deepcopy_node_attr(H, G)
|
||||
self.deepcopy_edge_attr(H, G)
|
||||
|
||||
def deepcopy_graph_attr(self, H, G):
|
||||
assert G.graph["foo"] == H.graph["foo"]
|
||||
G.graph["foo"].append(1)
|
||||
assert G.graph["foo"] != H.graph["foo"]
|
||||
|
||||
def deepcopy_node_attr(self, H, G):
|
||||
assert G.nodes[0]["foo"] == H.nodes[0]["foo"]
|
||||
G.nodes[0]["foo"].append(1)
|
||||
assert G.nodes[0]["foo"] != H.nodes[0]["foo"]
|
||||
|
||||
def deepcopy_edge_attr(self, H, G):
|
||||
assert G[1][2]["foo"] == H[1][2]["foo"]
|
||||
G[1][2]["foo"].append(1)
|
||||
assert G[1][2]["foo"] != H[1][2]["foo"]
|
||||
|
||||
def is_shallow_copy(self, H, G):
|
||||
self.graphs_equal(H, G)
|
||||
self.shallow_copy_attrdict(H, G)
|
||||
|
||||
def shallow_copy_attrdict(self, H, G):
|
||||
self.shallow_copy_graph_attr(H, G)
|
||||
self.shallow_copy_node_attr(H, G)
|
||||
self.shallow_copy_edge_attr(H, G)
|
||||
|
||||
def shallow_copy_graph_attr(self, H, G):
|
||||
assert G.graph["foo"] == H.graph["foo"]
|
||||
G.graph["foo"].append(1)
|
||||
assert G.graph["foo"] == H.graph["foo"]
|
||||
|
||||
def shallow_copy_node_attr(self, H, G):
|
||||
assert G.nodes[0]["foo"] == H.nodes[0]["foo"]
|
||||
G.nodes[0]["foo"].append(1)
|
||||
assert G.nodes[0]["foo"] == H.nodes[0]["foo"]
|
||||
|
||||
def shallow_copy_edge_attr(self, H, G):
|
||||
assert G[1][2]["foo"] == H[1][2]["foo"]
|
||||
G[1][2]["foo"].append(1)
|
||||
assert G[1][2]["foo"] == H[1][2]["foo"]
|
||||
|
||||
def same_attrdict(self, H, G):
|
||||
old_foo = H[1][2]["foo"]
|
||||
H.adj[1][2]["foo"] = "baz"
|
||||
assert G.edges == H.edges
|
||||
H.adj[1][2]["foo"] = old_foo
|
||||
assert G.edges == H.edges
|
||||
|
||||
old_foo = H.nodes[0]["foo"]
|
||||
H.nodes[0]["foo"] = "baz"
|
||||
assert G.nodes == H.nodes
|
||||
H.nodes[0]["foo"] = old_foo
|
||||
assert G.nodes == H.nodes
|
||||
|
||||
def different_attrdict(self, H, G):
|
||||
old_foo = H[1][2]["foo"]
|
||||
H.adj[1][2]["foo"] = "baz"
|
||||
assert G._adj != H._adj
|
||||
H.adj[1][2]["foo"] = old_foo
|
||||
assert G._adj == H._adj
|
||||
|
||||
old_foo = H.nodes[0]["foo"]
|
||||
H.nodes[0]["foo"] = "baz"
|
||||
assert G._node != H._node
|
||||
H.nodes[0]["foo"] = old_foo
|
||||
assert G._node == H._node
|
||||
|
||||
def graphs_equal(self, H, G):
|
||||
assert G._adj == H._adj
|
||||
assert G._node == H._node
|
||||
assert G.graph == H.graph
|
||||
assert G.name == H.name
|
||||
if not G.is_directed() and not H.is_directed():
|
||||
assert H._adj[1][2] is H._adj[2][1]
|
||||
assert G._adj[1][2] is G._adj[2][1]
|
||||
else: # at least one is directed
|
||||
if not G.is_directed():
|
||||
G._pred = G._adj
|
||||
G._succ = G._adj
|
||||
if not H.is_directed():
|
||||
H._pred = H._adj
|
||||
H._succ = H._adj
|
||||
assert G._pred == H._pred
|
||||
assert G._succ == H._succ
|
||||
assert H._succ[1][2] is H._pred[2][1]
|
||||
assert G._succ[1][2] is G._pred[2][1]
|
||||
|
||||
def test_graph_attr(self):
|
||||
G = self.K3.copy()
|
||||
G.graph["foo"] = "bar"
|
||||
assert isinstance(G.graph, G.graph_attr_dict_factory)
|
||||
assert G.graph["foo"] == "bar"
|
||||
del G.graph["foo"]
|
||||
assert G.graph == {}
|
||||
H = self.Graph(foo="bar")
|
||||
assert H.graph["foo"] == "bar"
|
||||
|
||||
def test_node_attr(self):
|
||||
G = self.K3.copy()
|
||||
G.add_node(1, foo="bar")
|
||||
assert all(
|
||||
isinstance(d, G.node_attr_dict_factory) for u, d in G.nodes(data=True)
|
||||
)
|
||||
assert nodes_equal(G.nodes(), [0, 1, 2])
|
||||
assert nodes_equal(G.nodes(data=True), [(0, {}), (1, {"foo": "bar"}), (2, {})])
|
||||
G.nodes[1]["foo"] = "baz"
|
||||
assert nodes_equal(G.nodes(data=True), [(0, {}), (1, {"foo": "baz"}), (2, {})])
|
||||
assert nodes_equal(G.nodes(data="foo"), [(0, None), (1, "baz"), (2, None)])
|
||||
assert nodes_equal(
|
||||
G.nodes(data="foo", default="bar"), [(0, "bar"), (1, "baz"), (2, "bar")]
|
||||
)
|
||||
|
||||
def test_node_attr2(self):
|
||||
G = self.K3.copy()
|
||||
a = {"foo": "bar"}
|
||||
G.add_node(3, **a)
|
||||
assert nodes_equal(G.nodes(), [0, 1, 2, 3])
|
||||
assert nodes_equal(
|
||||
G.nodes(data=True), [(0, {}), (1, {}), (2, {}), (3, {"foo": "bar"})]
|
||||
)
|
||||
|
||||
def test_edge_lookup(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 2, foo="bar")
|
||||
assert edges_equal(G.edges[1, 2], {"foo": "bar"})
|
||||
|
||||
def test_edge_attr(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 2, foo="bar")
|
||||
assert all(
|
||||
isinstance(d, G.edge_attr_dict_factory) for u, v, d in G.edges(data=True)
|
||||
)
|
||||
assert edges_equal(G.edges(data=True), [(1, 2, {"foo": "bar"})])
|
||||
assert edges_equal(G.edges(data="foo"), [(1, 2, "bar")])
|
||||
|
||||
def test_edge_attr2(self):
|
||||
G = self.Graph()
|
||||
G.add_edges_from([(1, 2), (3, 4)], foo="foo")
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"foo": "foo"}), (3, 4, {"foo": "foo"})]
|
||||
)
|
||||
assert edges_equal(G.edges(data="foo"), [(1, 2, "foo"), (3, 4, "foo")])
|
||||
|
||||
def test_edge_attr3(self):
|
||||
G = self.Graph()
|
||||
G.add_edges_from([(1, 2, {"weight": 32}), (3, 4, {"weight": 64})], foo="foo")
|
||||
assert edges_equal(
|
||||
G.edges(data=True),
|
||||
[
|
||||
(1, 2, {"foo": "foo", "weight": 32}),
|
||||
(3, 4, {"foo": "foo", "weight": 64}),
|
||||
],
|
||||
)
|
||||
|
||||
G.remove_edges_from([(1, 2), (3, 4)])
|
||||
G.add_edge(1, 2, data=7, spam="bar", bar="foo")
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"data": 7, "spam": "bar", "bar": "foo"})]
|
||||
)
|
||||
|
||||
def test_edge_attr4(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 2, data=7, spam="bar", bar="foo")
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"data": 7, "spam": "bar", "bar": "foo"})]
|
||||
)
|
||||
G[1][2]["data"] = 10 # OK to set data like this
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"data": 10, "spam": "bar", "bar": "foo"})]
|
||||
)
|
||||
|
||||
G.adj[1][2]["data"] = 20
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"data": 20, "spam": "bar", "bar": "foo"})]
|
||||
)
|
||||
G.edges[1, 2]["data"] = 21 # another spelling, "edge"
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"data": 21, "spam": "bar", "bar": "foo"})]
|
||||
)
|
||||
G.adj[1][2]["listdata"] = [20, 200]
|
||||
G.adj[1][2]["weight"] = 20
|
||||
dd = {
|
||||
"data": 21,
|
||||
"spam": "bar",
|
||||
"bar": "foo",
|
||||
"listdata": [20, 200],
|
||||
"weight": 20,
|
||||
}
|
||||
assert edges_equal(G.edges(data=True), [(1, 2, dd)])
|
||||
|
||||
def test_to_undirected(self):
|
||||
G = self.K3
|
||||
self.add_attributes(G)
|
||||
H = nx.Graph(G)
|
||||
self.is_shallow_copy(H, G)
|
||||
self.different_attrdict(H, G)
|
||||
H = G.to_undirected()
|
||||
self.is_deepcopy(H, G)
|
||||
|
||||
def test_to_directed_as_view(self):
|
||||
H = nx.path_graph(2, create_using=self.Graph)
|
||||
H2 = H.to_directed(as_view=True)
|
||||
assert H is H2._graph
|
||||
assert H2.has_edge(0, 1)
|
||||
assert H2.has_edge(1, 0) or H.is_directed()
|
||||
pytest.raises(nx.NetworkXError, H2.add_node, -1)
|
||||
pytest.raises(nx.NetworkXError, H2.add_edge, 1, 2)
|
||||
H.add_edge(1, 2)
|
||||
assert H2.has_edge(1, 2)
|
||||
assert H2.has_edge(2, 1) or H.is_directed()
|
||||
|
||||
def test_to_undirected_as_view(self):
|
||||
H = nx.path_graph(2, create_using=self.Graph)
|
||||
H2 = H.to_undirected(as_view=True)
|
||||
assert H is H2._graph
|
||||
assert H2.has_edge(0, 1)
|
||||
assert H2.has_edge(1, 0)
|
||||
pytest.raises(nx.NetworkXError, H2.add_node, -1)
|
||||
pytest.raises(nx.NetworkXError, H2.add_edge, 1, 2)
|
||||
H.add_edge(1, 2)
|
||||
assert H2.has_edge(1, 2)
|
||||
assert H2.has_edge(2, 1)
|
||||
|
||||
def test_directed_class(self):
|
||||
G = self.Graph()
|
||||
|
||||
class newGraph(G.to_undirected_class()):
|
||||
def to_directed_class(self):
|
||||
return newDiGraph
|
||||
|
||||
def to_undirected_class(self):
|
||||
return newGraph
|
||||
|
||||
class newDiGraph(G.to_directed_class()):
|
||||
def to_directed_class(self):
|
||||
return newDiGraph
|
||||
|
||||
def to_undirected_class(self):
|
||||
return newGraph
|
||||
|
||||
G = newDiGraph() if G.is_directed() else newGraph()
|
||||
H = G.to_directed()
|
||||
assert isinstance(H, newDiGraph)
|
||||
H = G.to_undirected()
|
||||
assert isinstance(H, newGraph)
|
||||
|
||||
def test_to_directed(self):
|
||||
G = self.K3
|
||||
self.add_attributes(G)
|
||||
H = nx.DiGraph(G)
|
||||
self.is_shallow_copy(H, G)
|
||||
self.different_attrdict(H, G)
|
||||
H = G.to_directed()
|
||||
self.is_deepcopy(H, G)
|
||||
|
||||
def test_subgraph(self):
|
||||
G = self.K3
|
||||
self.add_attributes(G)
|
||||
H = G.subgraph([0, 1, 2, 5])
|
||||
self.graphs_equal(H, G)
|
||||
self.same_attrdict(H, G)
|
||||
self.shallow_copy_attrdict(H, G)
|
||||
|
||||
H = G.subgraph(0)
|
||||
assert H.adj == {0: {}}
|
||||
H = G.subgraph([])
|
||||
assert H.adj == {}
|
||||
assert G.adj != {}
|
||||
|
||||
def test_selfloops_attr(self):
|
||||
G = self.K3.copy()
|
||||
G.add_edge(0, 0)
|
||||
G.add_edge(1, 1, weight=2)
|
||||
assert edges_equal(
|
||||
nx.selfloop_edges(G, data=True), [(0, 0, {}), (1, 1, {"weight": 2})]
|
||||
)
|
||||
assert edges_equal(
|
||||
nx.selfloop_edges(G, data="weight"), [(0, 0, None), (1, 1, 2)]
|
||||
)
|
||||
|
||||
|
||||
class TestGraph(BaseAttrGraphTester):
|
||||
"""Tests specific to dict-of-dict-of-dict graph data structure"""
|
||||
|
||||
def setup_method(self):
|
||||
self.Graph = nx.Graph
|
||||
# build dict-of-dict-of-dict K3
|
||||
ed1, ed2, ed3 = ({}, {}, {})
|
||||
self.k3adj = {0: {1: ed1, 2: ed2}, 1: {0: ed1, 2: ed3}, 2: {0: ed2, 1: ed3}}
|
||||
self.k3edges = [(0, 1), (0, 2), (1, 2)]
|
||||
self.k3nodes = [0, 1, 2]
|
||||
self.K3 = self.Graph()
|
||||
self.K3._adj = self.k3adj
|
||||
self.K3._node = {}
|
||||
self.K3._node[0] = {}
|
||||
self.K3._node[1] = {}
|
||||
self.K3._node[2] = {}
|
||||
|
||||
def test_pickle(self):
|
||||
G = self.K3
|
||||
pg = pickle.loads(pickle.dumps(G, -1))
|
||||
self.graphs_equal(pg, G)
|
||||
pg = pickle.loads(pickle.dumps(G))
|
||||
self.graphs_equal(pg, G)
|
||||
|
||||
def test_data_input(self):
|
||||
G = self.Graph({1: [2], 2: [1]}, name="test")
|
||||
assert G.name == "test"
|
||||
assert sorted(G.adj.items()) == [(1, {2: {}}), (2, {1: {}})]
|
||||
|
||||
def test_adjacency(self):
|
||||
G = self.K3
|
||||
assert dict(G.adjacency()) == {
|
||||
0: {1: {}, 2: {}},
|
||||
1: {0: {}, 2: {}},
|
||||
2: {0: {}, 1: {}},
|
||||
}
|
||||
|
||||
def test_getitem(self):
|
||||
G = self.K3
|
||||
assert G.adj[0] == {1: {}, 2: {}}
|
||||
assert G[0] == {1: {}, 2: {}}
|
||||
with pytest.raises(KeyError):
|
||||
G.__getitem__("j")
|
||||
with pytest.raises(TypeError):
|
||||
G.__getitem__(["A"])
|
||||
|
||||
def test_add_node(self):
|
||||
G = self.Graph()
|
||||
G.add_node(0)
|
||||
assert G.adj == {0: {}}
|
||||
# test add attributes
|
||||
G.add_node(1, c="red")
|
||||
G.add_node(2, c="blue")
|
||||
G.add_node(3, c="red")
|
||||
assert G.nodes[1]["c"] == "red"
|
||||
assert G.nodes[2]["c"] == "blue"
|
||||
assert G.nodes[3]["c"] == "red"
|
||||
# test updating attributes
|
||||
G.add_node(1, c="blue")
|
||||
G.add_node(2, c="red")
|
||||
G.add_node(3, c="blue")
|
||||
assert G.nodes[1]["c"] == "blue"
|
||||
assert G.nodes[2]["c"] == "red"
|
||||
assert G.nodes[3]["c"] == "blue"
|
||||
|
||||
def test_add_nodes_from(self):
|
||||
G = self.Graph()
|
||||
G.add_nodes_from([0, 1, 2])
|
||||
assert G.adj == {0: {}, 1: {}, 2: {}}
|
||||
# test add attributes
|
||||
G.add_nodes_from([0, 1, 2], c="red")
|
||||
assert G.nodes[0]["c"] == "red"
|
||||
assert G.nodes[2]["c"] == "red"
|
||||
# test that attribute dicts are not the same
|
||||
assert G.nodes[0] is not G.nodes[1]
|
||||
# test updating attributes
|
||||
G.add_nodes_from([0, 1, 2], c="blue")
|
||||
assert G.nodes[0]["c"] == "blue"
|
||||
assert G.nodes[2]["c"] == "blue"
|
||||
assert G.nodes[0] is not G.nodes[1]
|
||||
# test tuple input
|
||||
H = self.Graph()
|
||||
H.add_nodes_from(G.nodes(data=True))
|
||||
assert H.nodes[0]["c"] == "blue"
|
||||
assert H.nodes[2]["c"] == "blue"
|
||||
assert H.nodes[0] is not H.nodes[1]
|
||||
# specific overrides general
|
||||
H.add_nodes_from([0, (1, {"c": "green"}), (3, {"c": "cyan"})], c="red")
|
||||
assert H.nodes[0]["c"] == "red"
|
||||
assert H.nodes[1]["c"] == "green"
|
||||
assert H.nodes[2]["c"] == "blue"
|
||||
assert H.nodes[3]["c"] == "cyan"
|
||||
|
||||
def test_remove_node(self):
|
||||
G = self.K3.copy()
|
||||
G.remove_node(0)
|
||||
assert G.adj == {1: {2: {}}, 2: {1: {}}}
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.remove_node(-1)
|
||||
|
||||
# generator here to implement list,set,string...
|
||||
|
||||
def test_remove_nodes_from(self):
|
||||
G = self.K3.copy()
|
||||
G.remove_nodes_from([0, 1])
|
||||
assert G.adj == {2: {}}
|
||||
G.remove_nodes_from([-1]) # silent fail
|
||||
|
||||
def test_add_edge(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(0, 1)
|
||||
assert G.adj == {0: {1: {}}, 1: {0: {}}}
|
||||
G = self.Graph()
|
||||
G.add_edge(*(0, 1))
|
||||
assert G.adj == {0: {1: {}}, 1: {0: {}}}
|
||||
G = self.Graph()
|
||||
with pytest.raises(ValueError):
|
||||
G.add_edge(None, "anything")
|
||||
|
||||
def test_add_edges_from(self):
|
||||
G = self.Graph()
|
||||
G.add_edges_from([(0, 1), (0, 2, {"weight": 3})])
|
||||
assert G.adj == {
|
||||
0: {1: {}, 2: {"weight": 3}},
|
||||
1: {0: {}},
|
||||
2: {0: {"weight": 3}},
|
||||
}
|
||||
G = self.Graph()
|
||||
G.add_edges_from([(0, 1), (0, 2, {"weight": 3}), (1, 2, {"data": 4})], data=2)
|
||||
assert G.adj == {
|
||||
0: {1: {"data": 2}, 2: {"weight": 3, "data": 2}},
|
||||
1: {0: {"data": 2}, 2: {"data": 4}},
|
||||
2: {0: {"weight": 3, "data": 2}, 1: {"data": 4}},
|
||||
}
|
||||
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.add_edges_from([(0,)]) # too few in tuple
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.add_edges_from([(0, 1, 2, 3)]) # too many in tuple
|
||||
with pytest.raises(TypeError):
|
||||
G.add_edges_from([0]) # not a tuple
|
||||
with pytest.raises(ValueError):
|
||||
G.add_edges_from([(None, 3), (3, 2)]) # None cannot be a node
|
||||
|
||||
def test_remove_edge(self):
|
||||
G = self.K3.copy()
|
||||
G.remove_edge(0, 1)
|
||||
assert G.adj == {0: {2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}}
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.remove_edge(-1, 0)
|
||||
|
||||
def test_remove_edges_from(self):
|
||||
G = self.K3.copy()
|
||||
G.remove_edges_from([(0, 1)])
|
||||
assert G.adj == {0: {2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}}
|
||||
G.remove_edges_from([(0, 0)]) # silent fail
|
||||
|
||||
def test_clear(self):
|
||||
G = self.K3.copy()
|
||||
G.graph["name"] = "K3"
|
||||
G.clear()
|
||||
assert list(G.nodes) == []
|
||||
assert G.adj == {}
|
||||
assert G.graph == {}
|
||||
|
||||
def test_clear_edges(self):
|
||||
G = self.K3.copy()
|
||||
G.graph["name"] = "K3"
|
||||
nodes = list(G.nodes)
|
||||
G.clear_edges()
|
||||
assert list(G.nodes) == nodes
|
||||
assert G.adj == {0: {}, 1: {}, 2: {}}
|
||||
assert list(G.edges) == []
|
||||
assert G.graph["name"] == "K3"
|
||||
|
||||
def test_edges_data(self):
|
||||
G = self.K3
|
||||
all_edges = [(0, 1, {}), (0, 2, {}), (1, 2, {})]
|
||||
assert edges_equal(G.edges(data=True), all_edges)
|
||||
assert edges_equal(G.edges(0, data=True), [(0, 1, {}), (0, 2, {})])
|
||||
assert edges_equal(G.edges([0, 1], data=True), all_edges)
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.edges(-1, True)
|
||||
|
||||
def test_get_edge_data(self):
|
||||
G = self.K3.copy()
|
||||
assert G.get_edge_data(0, 1) == {}
|
||||
assert G[0][1] == {}
|
||||
assert G.get_edge_data(10, 20) is None
|
||||
assert G.get_edge_data(-1, 0) is None
|
||||
assert G.get_edge_data(-1, 0, default=1) == 1
|
||||
|
||||
def test_update(self):
|
||||
# specify both edgees and nodes
|
||||
G = self.K3.copy()
|
||||
G.update(nodes=[3, (4, {"size": 2})], edges=[(4, 5), (6, 7, {"weight": 2})])
|
||||
nlist = [
|
||||
(0, {}),
|
||||
(1, {}),
|
||||
(2, {}),
|
||||
(3, {}),
|
||||
(4, {"size": 2}),
|
||||
(5, {}),
|
||||
(6, {}),
|
||||
(7, {}),
|
||||
]
|
||||
assert sorted(G.nodes.data()) == nlist
|
||||
if G.is_directed():
|
||||
elist = [
|
||||
(0, 1, {}),
|
||||
(0, 2, {}),
|
||||
(1, 0, {}),
|
||||
(1, 2, {}),
|
||||
(2, 0, {}),
|
||||
(2, 1, {}),
|
||||
(4, 5, {}),
|
||||
(6, 7, {"weight": 2}),
|
||||
]
|
||||
else:
|
||||
elist = [
|
||||
(0, 1, {}),
|
||||
(0, 2, {}),
|
||||
(1, 2, {}),
|
||||
(4, 5, {}),
|
||||
(6, 7, {"weight": 2}),
|
||||
]
|
||||
assert sorted(G.edges.data()) == elist
|
||||
assert G.graph == {}
|
||||
|
||||
# no keywords -- order is edges, nodes
|
||||
G = self.K3.copy()
|
||||
G.update([(4, 5), (6, 7, {"weight": 2})], [3, (4, {"size": 2})])
|
||||
assert sorted(G.nodes.data()) == nlist
|
||||
assert sorted(G.edges.data()) == elist
|
||||
assert G.graph == {}
|
||||
|
||||
# update using only a graph
|
||||
G = self.Graph()
|
||||
G.graph["foo"] = "bar"
|
||||
G.add_node(2, data=4)
|
||||
G.add_edge(0, 1, weight=0.5)
|
||||
GG = G.copy()
|
||||
H = self.Graph()
|
||||
GG.update(H)
|
||||
assert graphs_equal(G, GG)
|
||||
H.update(G)
|
||||
assert graphs_equal(H, G)
|
||||
|
||||
# update nodes only
|
||||
H = self.Graph()
|
||||
H.update(nodes=[3, 4])
|
||||
assert H.nodes ^ {3, 4} == set()
|
||||
assert H.size() == 0
|
||||
|
||||
# update edges only
|
||||
H = self.Graph()
|
||||
H.update(edges=[(3, 4)])
|
||||
assert sorted(H.edges.data()) == [(3, 4, {})]
|
||||
assert H.size() == 1
|
||||
|
||||
# No inputs -> exception
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
nx.Graph().update()
|
||||
|
||||
|
||||
class TestEdgeSubgraph:
|
||||
"""Unit tests for the :meth:`Graph.edge_subgraph` method."""
|
||||
|
||||
def setup_method(self):
|
||||
# Create a path graph on five nodes.
|
||||
G = nx.path_graph(5)
|
||||
# Add some node, edge, and graph attributes.
|
||||
for i in range(5):
|
||||
G.nodes[i]["name"] = f"node{i}"
|
||||
G.edges[0, 1]["name"] = "edge01"
|
||||
G.edges[3, 4]["name"] = "edge34"
|
||||
G.graph["name"] = "graph"
|
||||
# Get the subgraph induced by the first and last edges.
|
||||
self.G = G
|
||||
self.H = G.edge_subgraph([(0, 1), (3, 4)])
|
||||
|
||||
def test_correct_nodes(self):
|
||||
"""Tests that the subgraph has the correct nodes."""
|
||||
assert [0, 1, 3, 4] == sorted(self.H.nodes())
|
||||
|
||||
def test_correct_edges(self):
|
||||
"""Tests that the subgraph has the correct edges."""
|
||||
assert [(0, 1, "edge01"), (3, 4, "edge34")] == sorted(self.H.edges(data="name"))
|
||||
|
||||
def test_add_node(self):
|
||||
"""Tests that adding a node to the original graph does not
|
||||
affect the nodes of the subgraph.
|
||||
|
||||
"""
|
||||
self.G.add_node(5)
|
||||
assert [0, 1, 3, 4] == sorted(self.H.nodes())
|
||||
|
||||
def test_remove_node(self):
|
||||
"""Tests that removing a node in the original graph does
|
||||
affect the nodes of the subgraph.
|
||||
|
||||
"""
|
||||
self.G.remove_node(0)
|
||||
assert [1, 3, 4] == sorted(self.H.nodes())
|
||||
|
||||
def test_node_attr_dict(self):
|
||||
"""Tests that the node attribute dictionary of the two graphs is
|
||||
the same object.
|
||||
|
||||
"""
|
||||
for v in self.H:
|
||||
assert self.G.nodes[v] == self.H.nodes[v]
|
||||
# Making a change to G should make a change in H and vice versa.
|
||||
self.G.nodes[0]["name"] = "foo"
|
||||
assert self.G.nodes[0] == self.H.nodes[0]
|
||||
self.H.nodes[1]["name"] = "bar"
|
||||
assert self.G.nodes[1] == self.H.nodes[1]
|
||||
|
||||
def test_edge_attr_dict(self):
|
||||
"""Tests that the edge attribute dictionary of the two graphs is
|
||||
the same object.
|
||||
|
||||
"""
|
||||
for u, v in self.H.edges():
|
||||
assert self.G.edges[u, v] == self.H.edges[u, v]
|
||||
# Making a change to G should make a change in H and vice versa.
|
||||
self.G.edges[0, 1]["name"] = "foo"
|
||||
assert self.G.edges[0, 1]["name"] == self.H.edges[0, 1]["name"]
|
||||
self.H.edges[3, 4]["name"] = "bar"
|
||||
assert self.G.edges[3, 4]["name"] == self.H.edges[3, 4]["name"]
|
||||
|
||||
def test_graph_attr_dict(self):
|
||||
"""Tests that the graph attribute dictionary of the two graphs
|
||||
is the same object.
|
||||
|
||||
"""
|
||||
assert self.G.graph is self.H.graph
|
||||
12
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_graph_historical.py
vendored
Normal file
12
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_graph_historical.py
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
"""Original NetworkX graph tests"""
|
||||
import networkx
|
||||
import networkx as nx
|
||||
|
||||
from .historical_tests import HistoricalTests
|
||||
|
||||
|
||||
class TestGraphHistorical(HistoricalTests):
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
HistoricalTests.setup_class()
|
||||
cls.G = nx.Graph
|
||||
352
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_graphviews.py
vendored
Normal file
352
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_graphviews.py
vendored
Normal file
@@ -0,0 +1,352 @@
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import edges_equal, nodes_equal
|
||||
|
||||
# Note: SubGraph views are not tested here. They have their own testing file
|
||||
|
||||
|
||||
class TestReverseView:
|
||||
def setup_method(self):
|
||||
self.G = nx.path_graph(9, create_using=nx.DiGraph())
|
||||
self.rv = nx.reverse_view(self.G)
|
||||
|
||||
def test_pickle(self):
|
||||
import pickle
|
||||
|
||||
rv = self.rv
|
||||
prv = pickle.loads(pickle.dumps(rv, -1))
|
||||
assert rv._node == prv._node
|
||||
assert rv._adj == prv._adj
|
||||
assert rv.graph == prv.graph
|
||||
|
||||
def test_contains(self):
|
||||
assert (2, 3) in self.G.edges
|
||||
assert (3, 2) not in self.G.edges
|
||||
assert (2, 3) not in self.rv.edges
|
||||
assert (3, 2) in self.rv.edges
|
||||
|
||||
def test_iter(self):
|
||||
expected = sorted(tuple(reversed(e)) for e in self.G.edges)
|
||||
assert sorted(self.rv.edges) == expected
|
||||
|
||||
def test_exceptions(self):
|
||||
nxg = nx.graphviews
|
||||
G = nx.Graph()
|
||||
pytest.raises(nx.NetworkXNotImplemented, nxg.reverse_view, G)
|
||||
|
||||
def test_subclass(self):
|
||||
class MyGraph(nx.DiGraph):
|
||||
def my_method(self):
|
||||
return "me"
|
||||
|
||||
def to_directed_class(self):
|
||||
return MyGraph()
|
||||
|
||||
M = MyGraph()
|
||||
M.add_edge(1, 2)
|
||||
RM = nx.reverse_view(M)
|
||||
print("RM class", RM.__class__)
|
||||
RMC = RM.copy()
|
||||
print("RMC class", RMC.__class__)
|
||||
print(RMC.edges)
|
||||
assert RMC.has_edge(2, 1)
|
||||
assert RMC.my_method() == "me"
|
||||
|
||||
|
||||
class TestMultiReverseView:
|
||||
def setup_method(self):
|
||||
self.G = nx.path_graph(9, create_using=nx.MultiDiGraph())
|
||||
self.G.add_edge(4, 5)
|
||||
self.rv = nx.reverse_view(self.G)
|
||||
|
||||
def test_pickle(self):
|
||||
import pickle
|
||||
|
||||
rv = self.rv
|
||||
prv = pickle.loads(pickle.dumps(rv, -1))
|
||||
assert rv._node == prv._node
|
||||
assert rv._adj == prv._adj
|
||||
assert rv.graph == prv.graph
|
||||
|
||||
def test_contains(self):
|
||||
assert (2, 3, 0) in self.G.edges
|
||||
assert (3, 2, 0) not in self.G.edges
|
||||
assert (2, 3, 0) not in self.rv.edges
|
||||
assert (3, 2, 0) in self.rv.edges
|
||||
assert (5, 4, 1) in self.rv.edges
|
||||
assert (4, 5, 1) not in self.rv.edges
|
||||
|
||||
def test_iter(self):
|
||||
expected = sorted((v, u, k) for u, v, k in self.G.edges)
|
||||
assert sorted(self.rv.edges) == expected
|
||||
|
||||
def test_exceptions(self):
|
||||
nxg = nx.graphviews
|
||||
MG = nx.MultiGraph(self.G)
|
||||
pytest.raises(nx.NetworkXNotImplemented, nxg.reverse_view, MG)
|
||||
|
||||
|
||||
def test_generic_multitype():
|
||||
nxg = nx.graphviews
|
||||
G = nx.DiGraph([(1, 2)])
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
nxg.generic_graph_view(G, create_using=nx.MultiGraph)
|
||||
G = nx.MultiDiGraph([(1, 2)])
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
nxg.generic_graph_view(G, create_using=nx.DiGraph)
|
||||
|
||||
|
||||
class TestToDirected:
|
||||
def setup_method(self):
|
||||
self.G = nx.path_graph(9)
|
||||
self.dv = nx.to_directed(self.G)
|
||||
self.MG = nx.path_graph(9, create_using=nx.MultiGraph())
|
||||
self.Mdv = nx.to_directed(self.MG)
|
||||
|
||||
def test_directed(self):
|
||||
assert not self.G.is_directed()
|
||||
assert self.dv.is_directed()
|
||||
|
||||
def test_already_directed(self):
|
||||
dd = nx.to_directed(self.dv)
|
||||
Mdd = nx.to_directed(self.Mdv)
|
||||
assert edges_equal(dd.edges, self.dv.edges)
|
||||
assert edges_equal(Mdd.edges, self.Mdv.edges)
|
||||
|
||||
def test_pickle(self):
|
||||
import pickle
|
||||
|
||||
dv = self.dv
|
||||
pdv = pickle.loads(pickle.dumps(dv, -1))
|
||||
assert dv._node == pdv._node
|
||||
assert dv._succ == pdv._succ
|
||||
assert dv._pred == pdv._pred
|
||||
assert dv.graph == pdv.graph
|
||||
|
||||
def test_contains(self):
|
||||
assert (2, 3) in self.G.edges
|
||||
assert (3, 2) in self.G.edges
|
||||
assert (2, 3) in self.dv.edges
|
||||
assert (3, 2) in self.dv.edges
|
||||
|
||||
def test_iter(self):
|
||||
revd = [tuple(reversed(e)) for e in self.G.edges]
|
||||
expected = sorted(list(self.G.edges) + revd)
|
||||
assert sorted(self.dv.edges) == expected
|
||||
|
||||
|
||||
class TestToUndirected:
|
||||
def setup_method(self):
|
||||
self.DG = nx.path_graph(9, create_using=nx.DiGraph())
|
||||
self.uv = nx.to_undirected(self.DG)
|
||||
self.MDG = nx.path_graph(9, create_using=nx.MultiDiGraph())
|
||||
self.Muv = nx.to_undirected(self.MDG)
|
||||
|
||||
def test_directed(self):
|
||||
assert self.DG.is_directed()
|
||||
assert not self.uv.is_directed()
|
||||
|
||||
def test_already_directed(self):
|
||||
uu = nx.to_undirected(self.uv)
|
||||
Muu = nx.to_undirected(self.Muv)
|
||||
assert edges_equal(uu.edges, self.uv.edges)
|
||||
assert edges_equal(Muu.edges, self.Muv.edges)
|
||||
|
||||
def test_pickle(self):
|
||||
import pickle
|
||||
|
||||
uv = self.uv
|
||||
puv = pickle.loads(pickle.dumps(uv, -1))
|
||||
assert uv._node == puv._node
|
||||
assert uv._adj == puv._adj
|
||||
assert uv.graph == puv.graph
|
||||
assert hasattr(uv, "_graph")
|
||||
|
||||
def test_contains(self):
|
||||
assert (2, 3) in self.DG.edges
|
||||
assert (3, 2) not in self.DG.edges
|
||||
assert (2, 3) in self.uv.edges
|
||||
assert (3, 2) in self.uv.edges
|
||||
|
||||
def test_iter(self):
|
||||
expected = sorted(self.DG.edges)
|
||||
assert sorted(self.uv.edges) == expected
|
||||
|
||||
|
||||
class TestChainsOfViews:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.G = nx.path_graph(9)
|
||||
cls.DG = nx.path_graph(9, create_using=nx.DiGraph())
|
||||
cls.MG = nx.path_graph(9, create_using=nx.MultiGraph())
|
||||
cls.MDG = nx.path_graph(9, create_using=nx.MultiDiGraph())
|
||||
cls.Gv = nx.to_undirected(cls.DG)
|
||||
cls.DGv = nx.to_directed(cls.G)
|
||||
cls.MGv = nx.to_undirected(cls.MDG)
|
||||
cls.MDGv = nx.to_directed(cls.MG)
|
||||
cls.Rv = cls.DG.reverse()
|
||||
cls.MRv = cls.MDG.reverse()
|
||||
cls.graphs = [
|
||||
cls.G,
|
||||
cls.DG,
|
||||
cls.MG,
|
||||
cls.MDG,
|
||||
cls.Gv,
|
||||
cls.DGv,
|
||||
cls.MGv,
|
||||
cls.MDGv,
|
||||
cls.Rv,
|
||||
cls.MRv,
|
||||
]
|
||||
for G in cls.graphs:
|
||||
G.edges, G.nodes, G.degree
|
||||
|
||||
def test_pickle(self):
|
||||
import pickle
|
||||
|
||||
for G in self.graphs:
|
||||
H = pickle.loads(pickle.dumps(G, -1))
|
||||
assert edges_equal(H.edges, G.edges)
|
||||
assert nodes_equal(H.nodes, G.nodes)
|
||||
|
||||
def test_subgraph_of_subgraph(self):
|
||||
SGv = nx.subgraph(self.G, range(3, 7))
|
||||
SDGv = nx.subgraph(self.DG, range(3, 7))
|
||||
SMGv = nx.subgraph(self.MG, range(3, 7))
|
||||
SMDGv = nx.subgraph(self.MDG, range(3, 7))
|
||||
for G in self.graphs + [SGv, SDGv, SMGv, SMDGv]:
|
||||
SG = nx.induced_subgraph(G, [4, 5, 6])
|
||||
assert list(SG) == [4, 5, 6]
|
||||
SSG = SG.subgraph([6, 7])
|
||||
assert list(SSG) == [6]
|
||||
# subgraph-subgraph chain is short-cut in base class method
|
||||
assert SSG._graph is G
|
||||
|
||||
def test_restricted_induced_subgraph_chains(self):
|
||||
"""Test subgraph chains that both restrict and show nodes/edges.
|
||||
|
||||
A restricted_view subgraph should allow induced subgraphs using
|
||||
G.subgraph that automagically without a chain (meaning the result
|
||||
is a subgraph view of the original graph not a subgraph-of-subgraph.
|
||||
"""
|
||||
hide_nodes = [3, 4, 5]
|
||||
hide_edges = [(6, 7)]
|
||||
RG = nx.restricted_view(self.G, hide_nodes, hide_edges)
|
||||
nodes = [4, 5, 6, 7, 8]
|
||||
SG = nx.induced_subgraph(RG, nodes)
|
||||
SSG = RG.subgraph(nodes)
|
||||
assert RG._graph is self.G
|
||||
assert SSG._graph is self.G
|
||||
assert SG._graph is RG
|
||||
assert edges_equal(SG.edges, SSG.edges)
|
||||
# should be same as morphing the graph
|
||||
CG = self.G.copy()
|
||||
CG.remove_nodes_from(hide_nodes)
|
||||
CG.remove_edges_from(hide_edges)
|
||||
assert edges_equal(CG.edges(nodes), SSG.edges)
|
||||
CG.remove_nodes_from([0, 1, 2, 3])
|
||||
assert edges_equal(CG.edges, SSG.edges)
|
||||
# switch order: subgraph first, then restricted view
|
||||
SSSG = self.G.subgraph(nodes)
|
||||
RSG = nx.restricted_view(SSSG, hide_nodes, hide_edges)
|
||||
assert RSG._graph is not self.G
|
||||
assert edges_equal(RSG.edges, CG.edges)
|
||||
|
||||
def test_subgraph_copy(self):
|
||||
for origG in self.graphs:
|
||||
G = nx.Graph(origG)
|
||||
SG = G.subgraph([4, 5, 6])
|
||||
H = SG.copy()
|
||||
assert type(G) == type(H)
|
||||
|
||||
def test_subgraph_todirected(self):
|
||||
SG = nx.induced_subgraph(self.G, [4, 5, 6])
|
||||
SSG = SG.to_directed()
|
||||
assert sorted(SSG) == [4, 5, 6]
|
||||
assert sorted(SSG.edges) == [(4, 5), (5, 4), (5, 6), (6, 5)]
|
||||
|
||||
def test_subgraph_toundirected(self):
|
||||
SG = nx.induced_subgraph(self.G, [4, 5, 6])
|
||||
SSG = SG.to_undirected()
|
||||
assert list(SSG) == [4, 5, 6]
|
||||
assert sorted(SSG.edges) == [(4, 5), (5, 6)]
|
||||
|
||||
def test_reverse_subgraph_toundirected(self):
|
||||
G = self.DG.reverse(copy=False)
|
||||
SG = G.subgraph([4, 5, 6])
|
||||
SSG = SG.to_undirected()
|
||||
assert list(SSG) == [4, 5, 6]
|
||||
assert sorted(SSG.edges) == [(4, 5), (5, 6)]
|
||||
|
||||
def test_reverse_reverse_copy(self):
|
||||
G = self.DG.reverse(copy=False)
|
||||
H = G.reverse(copy=True)
|
||||
assert H.nodes == self.DG.nodes
|
||||
assert H.edges == self.DG.edges
|
||||
G = self.MDG.reverse(copy=False)
|
||||
H = G.reverse(copy=True)
|
||||
assert H.nodes == self.MDG.nodes
|
||||
assert H.edges == self.MDG.edges
|
||||
|
||||
def test_subgraph_edgesubgraph_toundirected(self):
|
||||
G = self.G.copy()
|
||||
SG = G.subgraph([4, 5, 6])
|
||||
SSG = SG.edge_subgraph([(4, 5), (5, 4)])
|
||||
USSG = SSG.to_undirected()
|
||||
assert list(USSG) == [4, 5]
|
||||
assert sorted(USSG.edges) == [(4, 5)]
|
||||
|
||||
def test_copy_subgraph(self):
|
||||
G = self.G.copy()
|
||||
SG = G.subgraph([4, 5, 6])
|
||||
CSG = SG.copy(as_view=True)
|
||||
DCSG = SG.copy(as_view=False)
|
||||
assert hasattr(CSG, "_graph") # is a view
|
||||
assert not hasattr(DCSG, "_graph") # not a view
|
||||
|
||||
def test_copy_disubgraph(self):
|
||||
G = self.DG.copy()
|
||||
SG = G.subgraph([4, 5, 6])
|
||||
CSG = SG.copy(as_view=True)
|
||||
DCSG = SG.copy(as_view=False)
|
||||
assert hasattr(CSG, "_graph") # is a view
|
||||
assert not hasattr(DCSG, "_graph") # not a view
|
||||
|
||||
def test_copy_multidisubgraph(self):
|
||||
G = self.MDG.copy()
|
||||
SG = G.subgraph([4, 5, 6])
|
||||
CSG = SG.copy(as_view=True)
|
||||
DCSG = SG.copy(as_view=False)
|
||||
assert hasattr(CSG, "_graph") # is a view
|
||||
assert not hasattr(DCSG, "_graph") # not a view
|
||||
|
||||
def test_copy_multisubgraph(self):
|
||||
G = self.MG.copy()
|
||||
SG = G.subgraph([4, 5, 6])
|
||||
CSG = SG.copy(as_view=True)
|
||||
DCSG = SG.copy(as_view=False)
|
||||
assert hasattr(CSG, "_graph") # is a view
|
||||
assert not hasattr(DCSG, "_graph") # not a view
|
||||
|
||||
def test_copy_of_view(self):
|
||||
G = nx.MultiGraph(self.MGv)
|
||||
assert G.__class__.__name__ == "MultiGraph"
|
||||
G = G.copy(as_view=True)
|
||||
assert G.__class__.__name__ == "MultiGraph"
|
||||
|
||||
def test_subclass(self):
|
||||
class MyGraph(nx.DiGraph):
|
||||
def my_method(self):
|
||||
return "me"
|
||||
|
||||
def to_directed_class(self):
|
||||
return MyGraph()
|
||||
|
||||
for origG in self.graphs:
|
||||
G = MyGraph(origG)
|
||||
SG = G.subgraph([4, 5, 6])
|
||||
H = SG.copy()
|
||||
assert SG.my_method() == "me"
|
||||
assert H.my_method() == "me"
|
||||
assert 3 not in H or 3 in SG
|
||||
459
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_multidigraph.py
vendored
Normal file
459
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_multidigraph.py
vendored
Normal file
@@ -0,0 +1,459 @@
|
||||
from collections import UserDict
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import edges_equal
|
||||
|
||||
from .test_multigraph import BaseMultiGraphTester
|
||||
from .test_multigraph import TestEdgeSubgraph as _TestMultiGraphEdgeSubgraph
|
||||
from .test_multigraph import TestMultiGraph as _TestMultiGraph
|
||||
|
||||
|
||||
class BaseMultiDiGraphTester(BaseMultiGraphTester):
|
||||
def test_edges(self):
|
||||
G = self.K3
|
||||
edges = [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
|
||||
assert sorted(G.edges()) == edges
|
||||
assert sorted(G.edges(0)) == [(0, 1), (0, 2)]
|
||||
pytest.raises((KeyError, nx.NetworkXError), G.edges, -1)
|
||||
|
||||
def test_edges_data(self):
|
||||
G = self.K3
|
||||
edges = [(0, 1, {}), (0, 2, {}), (1, 0, {}), (1, 2, {}), (2, 0, {}), (2, 1, {})]
|
||||
assert sorted(G.edges(data=True)) == edges
|
||||
assert sorted(G.edges(0, data=True)) == [(0, 1, {}), (0, 2, {})]
|
||||
pytest.raises((KeyError, nx.NetworkXError), G.neighbors, -1)
|
||||
|
||||
def test_edges_multi(self):
|
||||
G = self.K3
|
||||
assert sorted(G.edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
|
||||
assert sorted(G.edges(0)) == [(0, 1), (0, 2)]
|
||||
G.add_edge(0, 1)
|
||||
assert sorted(G.edges()) == [
|
||||
(0, 1),
|
||||
(0, 1),
|
||||
(0, 2),
|
||||
(1, 0),
|
||||
(1, 2),
|
||||
(2, 0),
|
||||
(2, 1),
|
||||
]
|
||||
|
||||
def test_out_edges(self):
|
||||
G = self.K3
|
||||
assert sorted(G.out_edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
|
||||
assert sorted(G.out_edges(0)) == [(0, 1), (0, 2)]
|
||||
pytest.raises((KeyError, nx.NetworkXError), G.out_edges, -1)
|
||||
assert sorted(G.out_edges(0, keys=True)) == [(0, 1, 0), (0, 2, 0)]
|
||||
|
||||
def test_out_edges_multi(self):
|
||||
G = self.K3
|
||||
assert sorted(G.out_edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
|
||||
assert sorted(G.out_edges(0)) == [(0, 1), (0, 2)]
|
||||
G.add_edge(0, 1, 2)
|
||||
assert sorted(G.out_edges()) == [
|
||||
(0, 1),
|
||||
(0, 1),
|
||||
(0, 2),
|
||||
(1, 0),
|
||||
(1, 2),
|
||||
(2, 0),
|
||||
(2, 1),
|
||||
]
|
||||
|
||||
def test_out_edges_data(self):
|
||||
G = self.K3
|
||||
assert sorted(G.edges(0, data=True)) == [(0, 1, {}), (0, 2, {})]
|
||||
G.remove_edge(0, 1)
|
||||
G.add_edge(0, 1, data=1)
|
||||
assert sorted(G.edges(0, data=True)) == [(0, 1, {"data": 1}), (0, 2, {})]
|
||||
assert sorted(G.edges(0, data="data")) == [(0, 1, 1), (0, 2, None)]
|
||||
assert sorted(G.edges(0, data="data", default=-1)) == [(0, 1, 1), (0, 2, -1)]
|
||||
|
||||
def test_in_edges(self):
|
||||
G = self.K3
|
||||
assert sorted(G.in_edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
|
||||
assert sorted(G.in_edges(0)) == [(1, 0), (2, 0)]
|
||||
pytest.raises((KeyError, nx.NetworkXError), G.in_edges, -1)
|
||||
G.add_edge(0, 1, 2)
|
||||
assert sorted(G.in_edges()) == [
|
||||
(0, 1),
|
||||
(0, 1),
|
||||
(0, 2),
|
||||
(1, 0),
|
||||
(1, 2),
|
||||
(2, 0),
|
||||
(2, 1),
|
||||
]
|
||||
assert sorted(G.in_edges(0, keys=True)) == [(1, 0, 0), (2, 0, 0)]
|
||||
|
||||
def test_in_edges_no_keys(self):
|
||||
G = self.K3
|
||||
assert sorted(G.in_edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
|
||||
assert sorted(G.in_edges(0)) == [(1, 0), (2, 0)]
|
||||
G.add_edge(0, 1, 2)
|
||||
assert sorted(G.in_edges()) == [
|
||||
(0, 1),
|
||||
(0, 1),
|
||||
(0, 2),
|
||||
(1, 0),
|
||||
(1, 2),
|
||||
(2, 0),
|
||||
(2, 1),
|
||||
]
|
||||
|
||||
assert sorted(G.in_edges(data=True, keys=False)) == [
|
||||
(0, 1, {}),
|
||||
(0, 1, {}),
|
||||
(0, 2, {}),
|
||||
(1, 0, {}),
|
||||
(1, 2, {}),
|
||||
(2, 0, {}),
|
||||
(2, 1, {}),
|
||||
]
|
||||
|
||||
def test_in_edges_data(self):
|
||||
G = self.K3
|
||||
assert sorted(G.in_edges(0, data=True)) == [(1, 0, {}), (2, 0, {})]
|
||||
G.remove_edge(1, 0)
|
||||
G.add_edge(1, 0, data=1)
|
||||
assert sorted(G.in_edges(0, data=True)) == [(1, 0, {"data": 1}), (2, 0, {})]
|
||||
assert sorted(G.in_edges(0, data="data")) == [(1, 0, 1), (2, 0, None)]
|
||||
assert sorted(G.in_edges(0, data="data", default=-1)) == [(1, 0, 1), (2, 0, -1)]
|
||||
|
||||
def is_shallow(self, H, G):
|
||||
# graph
|
||||
assert G.graph["foo"] == H.graph["foo"]
|
||||
G.graph["foo"].append(1)
|
||||
assert G.graph["foo"] == H.graph["foo"]
|
||||
# node
|
||||
assert G.nodes[0]["foo"] == H.nodes[0]["foo"]
|
||||
G.nodes[0]["foo"].append(1)
|
||||
assert G.nodes[0]["foo"] == H.nodes[0]["foo"]
|
||||
# edge
|
||||
assert G[1][2][0]["foo"] == H[1][2][0]["foo"]
|
||||
G[1][2][0]["foo"].append(1)
|
||||
assert G[1][2][0]["foo"] == H[1][2][0]["foo"]
|
||||
|
||||
def is_deep(self, H, G):
|
||||
# graph
|
||||
assert G.graph["foo"] == H.graph["foo"]
|
||||
G.graph["foo"].append(1)
|
||||
assert G.graph["foo"] != H.graph["foo"]
|
||||
# node
|
||||
assert G.nodes[0]["foo"] == H.nodes[0]["foo"]
|
||||
G.nodes[0]["foo"].append(1)
|
||||
assert G.nodes[0]["foo"] != H.nodes[0]["foo"]
|
||||
# edge
|
||||
assert G[1][2][0]["foo"] == H[1][2][0]["foo"]
|
||||
G[1][2][0]["foo"].append(1)
|
||||
assert G[1][2][0]["foo"] != H[1][2][0]["foo"]
|
||||
|
||||
def test_to_undirected(self):
|
||||
# MultiDiGraph -> MultiGraph changes number of edges so it is
|
||||
# not a copy operation... use is_shallow, not is_shallow_copy
|
||||
G = self.K3
|
||||
self.add_attributes(G)
|
||||
H = nx.MultiGraph(G)
|
||||
# self.is_shallow(H,G)
|
||||
# the result is traversal order dependent so we
|
||||
# can't use the is_shallow() test here.
|
||||
try:
|
||||
assert edges_equal(H.edges(), [(0, 1), (1, 2), (2, 0)])
|
||||
except AssertionError:
|
||||
assert edges_equal(H.edges(), [(0, 1), (1, 2), (1, 2), (2, 0)])
|
||||
H = G.to_undirected()
|
||||
self.is_deep(H, G)
|
||||
|
||||
def test_has_successor(self):
|
||||
G = self.K3
|
||||
assert G.has_successor(0, 1)
|
||||
assert not G.has_successor(0, -1)
|
||||
|
||||
def test_successors(self):
|
||||
G = self.K3
|
||||
assert sorted(G.successors(0)) == [1, 2]
|
||||
pytest.raises((KeyError, nx.NetworkXError), G.successors, -1)
|
||||
|
||||
def test_has_predecessor(self):
|
||||
G = self.K3
|
||||
assert G.has_predecessor(0, 1)
|
||||
assert not G.has_predecessor(0, -1)
|
||||
|
||||
def test_predecessors(self):
|
||||
G = self.K3
|
||||
assert sorted(G.predecessors(0)) == [1, 2]
|
||||
pytest.raises((KeyError, nx.NetworkXError), G.predecessors, -1)
|
||||
|
||||
def test_degree(self):
|
||||
G = self.K3
|
||||
assert sorted(G.degree()) == [(0, 4), (1, 4), (2, 4)]
|
||||
assert dict(G.degree()) == {0: 4, 1: 4, 2: 4}
|
||||
assert G.degree(0) == 4
|
||||
assert list(G.degree(iter([0]))) == [(0, 4)]
|
||||
G.add_edge(0, 1, weight=0.3, other=1.2)
|
||||
assert sorted(G.degree(weight="weight")) == [(0, 4.3), (1, 4.3), (2, 4)]
|
||||
assert sorted(G.degree(weight="other")) == [(0, 5.2), (1, 5.2), (2, 4)]
|
||||
|
||||
def test_in_degree(self):
|
||||
G = self.K3
|
||||
assert sorted(G.in_degree()) == [(0, 2), (1, 2), (2, 2)]
|
||||
assert dict(G.in_degree()) == {0: 2, 1: 2, 2: 2}
|
||||
assert G.in_degree(0) == 2
|
||||
assert list(G.in_degree(iter([0]))) == [(0, 2)]
|
||||
assert G.in_degree(0, weight="weight") == 2
|
||||
|
||||
def test_out_degree(self):
|
||||
G = self.K3
|
||||
assert sorted(G.out_degree()) == [(0, 2), (1, 2), (2, 2)]
|
||||
assert dict(G.out_degree()) == {0: 2, 1: 2, 2: 2}
|
||||
assert G.out_degree(0) == 2
|
||||
assert list(G.out_degree(iter([0]))) == [(0, 2)]
|
||||
assert G.out_degree(0, weight="weight") == 2
|
||||
|
||||
def test_size(self):
|
||||
G = self.K3
|
||||
assert G.size() == 6
|
||||
assert G.number_of_edges() == 6
|
||||
G.add_edge(0, 1, weight=0.3, other=1.2)
|
||||
assert round(G.size(weight="weight"), 2) == 6.3
|
||||
assert round(G.size(weight="other"), 2) == 7.2
|
||||
|
||||
def test_to_undirected_reciprocal(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 2)
|
||||
assert G.to_undirected().has_edge(1, 2)
|
||||
assert not G.to_undirected(reciprocal=True).has_edge(1, 2)
|
||||
G.add_edge(2, 1)
|
||||
assert G.to_undirected(reciprocal=True).has_edge(1, 2)
|
||||
|
||||
def test_reverse_copy(self):
|
||||
G = nx.MultiDiGraph([(0, 1), (0, 1)])
|
||||
R = G.reverse()
|
||||
assert sorted(R.edges()) == [(1, 0), (1, 0)]
|
||||
R.remove_edge(1, 0)
|
||||
assert sorted(R.edges()) == [(1, 0)]
|
||||
assert sorted(G.edges()) == [(0, 1), (0, 1)]
|
||||
|
||||
def test_reverse_nocopy(self):
|
||||
G = nx.MultiDiGraph([(0, 1), (0, 1)])
|
||||
R = G.reverse(copy=False)
|
||||
assert sorted(R.edges()) == [(1, 0), (1, 0)]
|
||||
pytest.raises(nx.NetworkXError, R.remove_edge, 1, 0)
|
||||
|
||||
def test_di_attributes_cached(self):
|
||||
G = self.K3.copy()
|
||||
assert id(G.in_edges) == id(G.in_edges)
|
||||
assert id(G.out_edges) == id(G.out_edges)
|
||||
assert id(G.in_degree) == id(G.in_degree)
|
||||
assert id(G.out_degree) == id(G.out_degree)
|
||||
assert id(G.succ) == id(G.succ)
|
||||
assert id(G.pred) == id(G.pred)
|
||||
|
||||
|
||||
class TestMultiDiGraph(BaseMultiDiGraphTester, _TestMultiGraph):
|
||||
def setup_method(self):
|
||||
self.Graph = nx.MultiDiGraph
|
||||
# build K3
|
||||
self.k3edges = [(0, 1), (0, 2), (1, 2)]
|
||||
self.k3nodes = [0, 1, 2]
|
||||
self.K3 = self.Graph()
|
||||
self.K3._succ = {0: {}, 1: {}, 2: {}}
|
||||
# K3._adj is synced with K3._succ
|
||||
self.K3._pred = {0: {}, 1: {}, 2: {}}
|
||||
for u in self.k3nodes:
|
||||
for v in self.k3nodes:
|
||||
if u == v:
|
||||
continue
|
||||
d = {0: {}}
|
||||
self.K3._succ[u][v] = d
|
||||
self.K3._pred[v][u] = d
|
||||
self.K3._node = {}
|
||||
self.K3._node[0] = {}
|
||||
self.K3._node[1] = {}
|
||||
self.K3._node[2] = {}
|
||||
|
||||
def test_add_edge(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(0, 1)
|
||||
assert G._adj == {0: {1: {0: {}}}, 1: {}}
|
||||
assert G._succ == {0: {1: {0: {}}}, 1: {}}
|
||||
assert G._pred == {0: {}, 1: {0: {0: {}}}}
|
||||
G = self.Graph()
|
||||
G.add_edge(*(0, 1))
|
||||
assert G._adj == {0: {1: {0: {}}}, 1: {}}
|
||||
assert G._succ == {0: {1: {0: {}}}, 1: {}}
|
||||
assert G._pred == {0: {}, 1: {0: {0: {}}}}
|
||||
with pytest.raises(ValueError, match="None cannot be a node"):
|
||||
G.add_edge(None, 3)
|
||||
|
||||
def test_add_edges_from(self):
|
||||
G = self.Graph()
|
||||
G.add_edges_from([(0, 1), (0, 1, {"weight": 3})])
|
||||
assert G._adj == {0: {1: {0: {}, 1: {"weight": 3}}}, 1: {}}
|
||||
assert G._succ == {0: {1: {0: {}, 1: {"weight": 3}}}, 1: {}}
|
||||
assert G._pred == {0: {}, 1: {0: {0: {}, 1: {"weight": 3}}}}
|
||||
|
||||
G.add_edges_from([(0, 1), (0, 1, {"weight": 3})], weight=2)
|
||||
assert G._succ == {
|
||||
0: {1: {0: {}, 1: {"weight": 3}, 2: {"weight": 2}, 3: {"weight": 3}}},
|
||||
1: {},
|
||||
}
|
||||
assert G._pred == {
|
||||
0: {},
|
||||
1: {0: {0: {}, 1: {"weight": 3}, 2: {"weight": 2}, 3: {"weight": 3}}},
|
||||
}
|
||||
|
||||
G = self.Graph()
|
||||
edges = [
|
||||
(0, 1, {"weight": 3}),
|
||||
(0, 1, (("weight", 2),)),
|
||||
(0, 1, 5),
|
||||
(0, 1, "s"),
|
||||
]
|
||||
G.add_edges_from(edges)
|
||||
keydict = {0: {"weight": 3}, 1: {"weight": 2}, 5: {}, "s": {}}
|
||||
assert G._succ == {0: {1: keydict}, 1: {}}
|
||||
assert G._pred == {1: {0: keydict}, 0: {}}
|
||||
|
||||
# too few in tuple
|
||||
pytest.raises(nx.NetworkXError, G.add_edges_from, [(0,)])
|
||||
# too many in tuple
|
||||
pytest.raises(nx.NetworkXError, G.add_edges_from, [(0, 1, 2, 3, 4)])
|
||||
# not a tuple
|
||||
pytest.raises(TypeError, G.add_edges_from, [0])
|
||||
with pytest.raises(ValueError, match="None cannot be a node"):
|
||||
G.add_edges_from([(None, 3), (3, 2)])
|
||||
|
||||
def test_remove_edge(self):
|
||||
G = self.K3
|
||||
G.remove_edge(0, 1)
|
||||
assert G._succ == {
|
||||
0: {2: {0: {}}},
|
||||
1: {0: {0: {}}, 2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
assert G._pred == {
|
||||
0: {1: {0: {}}, 2: {0: {}}},
|
||||
1: {2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
pytest.raises((KeyError, nx.NetworkXError), G.remove_edge, -1, 0)
|
||||
pytest.raises((KeyError, nx.NetworkXError), G.remove_edge, 0, 2, key=1)
|
||||
|
||||
def test_remove_multiedge(self):
|
||||
G = self.K3
|
||||
G.add_edge(0, 1, key="parallel edge")
|
||||
G.remove_edge(0, 1, key="parallel edge")
|
||||
assert G._adj == {
|
||||
0: {1: {0: {}}, 2: {0: {}}},
|
||||
1: {0: {0: {}}, 2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
|
||||
assert G._succ == {
|
||||
0: {1: {0: {}}, 2: {0: {}}},
|
||||
1: {0: {0: {}}, 2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
|
||||
assert G._pred == {
|
||||
0: {1: {0: {}}, 2: {0: {}}},
|
||||
1: {0: {0: {}}, 2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
G.remove_edge(0, 1)
|
||||
assert G._succ == {
|
||||
0: {2: {0: {}}},
|
||||
1: {0: {0: {}}, 2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
assert G._pred == {
|
||||
0: {1: {0: {}}, 2: {0: {}}},
|
||||
1: {2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
pytest.raises((KeyError, nx.NetworkXError), G.remove_edge, -1, 0)
|
||||
|
||||
def test_remove_edges_from(self):
|
||||
G = self.K3
|
||||
G.remove_edges_from([(0, 1)])
|
||||
assert G._succ == {
|
||||
0: {2: {0: {}}},
|
||||
1: {0: {0: {}}, 2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
assert G._pred == {
|
||||
0: {1: {0: {}}, 2: {0: {}}},
|
||||
1: {2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
G.remove_edges_from([(0, 0)]) # silent fail
|
||||
|
||||
|
||||
class TestEdgeSubgraph(_TestMultiGraphEdgeSubgraph):
|
||||
"""Unit tests for the :meth:`MultiDiGraph.edge_subgraph` method."""
|
||||
|
||||
def setup_method(self):
|
||||
# Create a quadruply-linked path graph on five nodes.
|
||||
G = nx.MultiDiGraph()
|
||||
nx.add_path(G, range(5))
|
||||
nx.add_path(G, range(5))
|
||||
nx.add_path(G, reversed(range(5)))
|
||||
nx.add_path(G, reversed(range(5)))
|
||||
# Add some node, edge, and graph attributes.
|
||||
for i in range(5):
|
||||
G.nodes[i]["name"] = f"node{i}"
|
||||
G.adj[0][1][0]["name"] = "edge010"
|
||||
G.adj[0][1][1]["name"] = "edge011"
|
||||
G.adj[3][4][0]["name"] = "edge340"
|
||||
G.adj[3][4][1]["name"] = "edge341"
|
||||
G.graph["name"] = "graph"
|
||||
# Get the subgraph induced by one of the first edges and one of
|
||||
# the last edges.
|
||||
self.G = G
|
||||
self.H = G.edge_subgraph([(0, 1, 0), (3, 4, 1)])
|
||||
|
||||
|
||||
class CustomDictClass(UserDict):
|
||||
pass
|
||||
|
||||
|
||||
class MultiDiGraphSubClass(nx.MultiDiGraph):
|
||||
node_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
node_attr_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
adjlist_outer_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
adjlist_inner_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
edge_key_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
edge_attr_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
graph_attr_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
|
||||
|
||||
class TestMultiDiGraphSubclass(TestMultiDiGraph):
|
||||
def setup_method(self):
|
||||
self.Graph = MultiDiGraphSubClass
|
||||
# build K3
|
||||
self.k3edges = [(0, 1), (0, 2), (1, 2)]
|
||||
self.k3nodes = [0, 1, 2]
|
||||
self.K3 = self.Graph()
|
||||
self.K3._succ = self.K3.adjlist_outer_dict_factory(
|
||||
{
|
||||
0: self.K3.adjlist_inner_dict_factory(),
|
||||
1: self.K3.adjlist_inner_dict_factory(),
|
||||
2: self.K3.adjlist_inner_dict_factory(),
|
||||
}
|
||||
)
|
||||
# K3._adj is synced with K3._succ
|
||||
self.K3._pred = {0: {}, 1: {}, 2: {}}
|
||||
for u in self.k3nodes:
|
||||
for v in self.k3nodes:
|
||||
if u == v:
|
||||
continue
|
||||
d = {0: {}}
|
||||
self.K3._succ[u][v] = d
|
||||
self.K3._pred[v][u] = d
|
||||
self.K3._node = self.K3.node_dict_factory()
|
||||
self.K3._node[0] = self.K3.node_attr_dict_factory()
|
||||
self.K3._node[1] = self.K3.node_attr_dict_factory()
|
||||
self.K3._node[2] = self.K3.node_attr_dict_factory()
|
||||
528
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_multigraph.py
vendored
Normal file
528
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_multigraph.py
vendored
Normal file
@@ -0,0 +1,528 @@
|
||||
from collections import UserDict
|
||||
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import edges_equal
|
||||
|
||||
from .test_graph import BaseAttrGraphTester
|
||||
from .test_graph import TestGraph as _TestGraph
|
||||
|
||||
|
||||
class BaseMultiGraphTester(BaseAttrGraphTester):
|
||||
def test_has_edge(self):
|
||||
G = self.K3
|
||||
assert G.has_edge(0, 1)
|
||||
assert not G.has_edge(0, -1)
|
||||
assert G.has_edge(0, 1, 0)
|
||||
assert not G.has_edge(0, 1, 1)
|
||||
|
||||
def test_get_edge_data(self):
|
||||
G = self.K3
|
||||
assert G.get_edge_data(0, 1) == {0: {}}
|
||||
assert G[0][1] == {0: {}}
|
||||
assert G[0][1][0] == {}
|
||||
assert G.get_edge_data(10, 20) is None
|
||||
assert G.get_edge_data(0, 1, 0) == {}
|
||||
|
||||
def test_adjacency(self):
|
||||
G = self.K3
|
||||
assert dict(G.adjacency()) == {
|
||||
0: {1: {0: {}}, 2: {0: {}}},
|
||||
1: {0: {0: {}}, 2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
|
||||
def deepcopy_edge_attr(self, H, G):
|
||||
assert G[1][2][0]["foo"] == H[1][2][0]["foo"]
|
||||
G[1][2][0]["foo"].append(1)
|
||||
assert G[1][2][0]["foo"] != H[1][2][0]["foo"]
|
||||
|
||||
def shallow_copy_edge_attr(self, H, G):
|
||||
assert G[1][2][0]["foo"] == H[1][2][0]["foo"]
|
||||
G[1][2][0]["foo"].append(1)
|
||||
assert G[1][2][0]["foo"] == H[1][2][0]["foo"]
|
||||
|
||||
def graphs_equal(self, H, G):
|
||||
assert G._adj == H._adj
|
||||
assert G._node == H._node
|
||||
assert G.graph == H.graph
|
||||
assert G.name == H.name
|
||||
if not G.is_directed() and not H.is_directed():
|
||||
assert H._adj[1][2][0] is H._adj[2][1][0]
|
||||
assert G._adj[1][2][0] is G._adj[2][1][0]
|
||||
else: # at least one is directed
|
||||
if not G.is_directed():
|
||||
G._pred = G._adj
|
||||
G._succ = G._adj
|
||||
if not H.is_directed():
|
||||
H._pred = H._adj
|
||||
H._succ = H._adj
|
||||
assert G._pred == H._pred
|
||||
assert G._succ == H._succ
|
||||
assert H._succ[1][2][0] is H._pred[2][1][0]
|
||||
assert G._succ[1][2][0] is G._pred[2][1][0]
|
||||
|
||||
def same_attrdict(self, H, G):
|
||||
# same attrdict in the edgedata
|
||||
old_foo = H[1][2][0]["foo"]
|
||||
H.adj[1][2][0]["foo"] = "baz"
|
||||
assert G._adj == H._adj
|
||||
H.adj[1][2][0]["foo"] = old_foo
|
||||
assert G._adj == H._adj
|
||||
|
||||
old_foo = H.nodes[0]["foo"]
|
||||
H.nodes[0]["foo"] = "baz"
|
||||
assert G._node == H._node
|
||||
H.nodes[0]["foo"] = old_foo
|
||||
assert G._node == H._node
|
||||
|
||||
def different_attrdict(self, H, G):
|
||||
# used by graph_equal_but_different
|
||||
old_foo = H[1][2][0]["foo"]
|
||||
H.adj[1][2][0]["foo"] = "baz"
|
||||
assert G._adj != H._adj
|
||||
H.adj[1][2][0]["foo"] = old_foo
|
||||
assert G._adj == H._adj
|
||||
|
||||
old_foo = H.nodes[0]["foo"]
|
||||
H.nodes[0]["foo"] = "baz"
|
||||
assert G._node != H._node
|
||||
H.nodes[0]["foo"] = old_foo
|
||||
assert G._node == H._node
|
||||
|
||||
def test_to_undirected(self):
|
||||
G = self.K3
|
||||
self.add_attributes(G)
|
||||
H = nx.MultiGraph(G)
|
||||
self.is_shallow_copy(H, G)
|
||||
H = G.to_undirected()
|
||||
self.is_deepcopy(H, G)
|
||||
|
||||
def test_to_directed(self):
|
||||
G = self.K3
|
||||
self.add_attributes(G)
|
||||
H = nx.MultiDiGraph(G)
|
||||
self.is_shallow_copy(H, G)
|
||||
H = G.to_directed()
|
||||
self.is_deepcopy(H, G)
|
||||
|
||||
def test_number_of_edges_selfloops(self):
|
||||
G = self.K3
|
||||
G.add_edge(0, 0)
|
||||
G.add_edge(0, 0)
|
||||
G.add_edge(0, 0, key="parallel edge")
|
||||
G.remove_edge(0, 0, key="parallel edge")
|
||||
assert G.number_of_edges(0, 0) == 2
|
||||
G.remove_edge(0, 0)
|
||||
assert G.number_of_edges(0, 0) == 1
|
||||
|
||||
def test_edge_lookup(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 2, foo="bar")
|
||||
G.add_edge(1, 2, "key", foo="biz")
|
||||
assert edges_equal(G.edges[1, 2, 0], {"foo": "bar"})
|
||||
assert edges_equal(G.edges[1, 2, "key"], {"foo": "biz"})
|
||||
|
||||
def test_edge_attr(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 2, key="k1", foo="bar")
|
||||
G.add_edge(1, 2, key="k2", foo="baz")
|
||||
assert isinstance(G.get_edge_data(1, 2), G.edge_key_dict_factory)
|
||||
assert all(
|
||||
isinstance(d, G.edge_attr_dict_factory) for u, v, d in G.edges(data=True)
|
||||
)
|
||||
assert edges_equal(
|
||||
G.edges(keys=True, data=True),
|
||||
[(1, 2, "k1", {"foo": "bar"}), (1, 2, "k2", {"foo": "baz"})],
|
||||
)
|
||||
assert edges_equal(
|
||||
G.edges(keys=True, data="foo"), [(1, 2, "k1", "bar"), (1, 2, "k2", "baz")]
|
||||
)
|
||||
|
||||
def test_edge_attr4(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(1, 2, key=0, data=7, spam="bar", bar="foo")
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"data": 7, "spam": "bar", "bar": "foo"})]
|
||||
)
|
||||
G[1][2][0]["data"] = 10 # OK to set data like this
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"data": 10, "spam": "bar", "bar": "foo"})]
|
||||
)
|
||||
|
||||
G.adj[1][2][0]["data"] = 20
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"data": 20, "spam": "bar", "bar": "foo"})]
|
||||
)
|
||||
G.edges[1, 2, 0]["data"] = 21 # another spelling, "edge"
|
||||
assert edges_equal(
|
||||
G.edges(data=True), [(1, 2, {"data": 21, "spam": "bar", "bar": "foo"})]
|
||||
)
|
||||
G.adj[1][2][0]["listdata"] = [20, 200]
|
||||
G.adj[1][2][0]["weight"] = 20
|
||||
assert edges_equal(
|
||||
G.edges(data=True),
|
||||
[
|
||||
(
|
||||
1,
|
||||
2,
|
||||
{
|
||||
"data": 21,
|
||||
"spam": "bar",
|
||||
"bar": "foo",
|
||||
"listdata": [20, 200],
|
||||
"weight": 20,
|
||||
},
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
class TestMultiGraph(BaseMultiGraphTester, _TestGraph):
|
||||
def setup_method(self):
|
||||
self.Graph = nx.MultiGraph
|
||||
# build K3
|
||||
ed1, ed2, ed3 = ({0: {}}, {0: {}}, {0: {}})
|
||||
self.k3adj = {0: {1: ed1, 2: ed2}, 1: {0: ed1, 2: ed3}, 2: {0: ed2, 1: ed3}}
|
||||
self.k3edges = [(0, 1), (0, 2), (1, 2)]
|
||||
self.k3nodes = [0, 1, 2]
|
||||
self.K3 = self.Graph()
|
||||
self.K3._adj = self.k3adj
|
||||
self.K3._node = {}
|
||||
self.K3._node[0] = {}
|
||||
self.K3._node[1] = {}
|
||||
self.K3._node[2] = {}
|
||||
|
||||
def test_data_input(self):
|
||||
G = self.Graph({1: [2], 2: [1]}, name="test")
|
||||
assert G.name == "test"
|
||||
expected = [(1, {2: {0: {}}}), (2, {1: {0: {}}})]
|
||||
assert sorted(G.adj.items()) == expected
|
||||
|
||||
def test_data_multigraph_input(self):
|
||||
# standard case with edge keys and edge data
|
||||
edata0 = {"w": 200, "s": "foo"}
|
||||
edata1 = {"w": 201, "s": "bar"}
|
||||
keydict = {0: edata0, 1: edata1}
|
||||
dododod = {"a": {"b": keydict}}
|
||||
|
||||
multiple_edge = [("a", "b", 0, edata0), ("a", "b", 1, edata1)]
|
||||
single_edge = [("a", "b", 0, keydict)]
|
||||
|
||||
G = self.Graph(dododod, multigraph_input=True)
|
||||
assert list(G.edges(keys=True, data=True)) == multiple_edge
|
||||
G = self.Graph(dododod, multigraph_input=None)
|
||||
assert list(G.edges(keys=True, data=True)) == multiple_edge
|
||||
G = self.Graph(dododod, multigraph_input=False)
|
||||
assert list(G.edges(keys=True, data=True)) == single_edge
|
||||
|
||||
# test round-trip to_dict_of_dict and MultiGraph constructor
|
||||
G = self.Graph(dododod, multigraph_input=True)
|
||||
H = self.Graph(nx.to_dict_of_dicts(G))
|
||||
assert nx.is_isomorphic(G, H) is True # test that default is True
|
||||
for mgi in [True, False]:
|
||||
H = self.Graph(nx.to_dict_of_dicts(G), multigraph_input=mgi)
|
||||
assert nx.is_isomorphic(G, H) == mgi
|
||||
|
||||
# Set up cases for when incoming_graph_data is not multigraph_input
|
||||
etraits = {"w": 200, "s": "foo"}
|
||||
egraphics = {"color": "blue", "shape": "box"}
|
||||
edata = {"traits": etraits, "graphics": egraphics}
|
||||
dodod1 = {"a": {"b": edata}}
|
||||
dodod2 = {"a": {"b": etraits}}
|
||||
dodod3 = {"a": {"b": {"traits": etraits, "s": "foo"}}}
|
||||
dol = {"a": ["b"]}
|
||||
|
||||
multiple_edge = [("a", "b", "traits", etraits), ("a", "b", "graphics", egraphics)]
|
||||
single_edge = [("a", "b", 0, {})] # type: ignore[var-annotated]
|
||||
single_edge1 = [("a", "b", 0, edata)]
|
||||
single_edge2 = [("a", "b", 0, etraits)]
|
||||
single_edge3 = [("a", "b", 0, {"traits": etraits, "s": "foo"})]
|
||||
|
||||
cases = [ # (dod, mgi, edges)
|
||||
(dodod1, True, multiple_edge),
|
||||
(dodod1, False, single_edge1),
|
||||
(dodod2, False, single_edge2),
|
||||
(dodod3, False, single_edge3),
|
||||
(dol, False, single_edge),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("dod, mgi, edges", cases)
|
||||
def test_non_multigraph_input(self, dod, mgi, edges):
|
||||
G = self.Graph(dod, multigraph_input=mgi)
|
||||
assert list(G.edges(keys=True, data=True)) == edges
|
||||
G = nx.to_networkx_graph(dod, create_using=self.Graph, multigraph_input=mgi)
|
||||
assert list(G.edges(keys=True, data=True)) == edges
|
||||
|
||||
mgi_none_cases = [
|
||||
(dodod1, multiple_edge),
|
||||
(dodod2, single_edge2),
|
||||
(dodod3, single_edge3),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("dod, edges", mgi_none_cases)
|
||||
def test_non_multigraph_input_mgi_none(self, dod, edges):
|
||||
# test constructor without to_networkx_graph for mgi=None
|
||||
G = self.Graph(dod)
|
||||
assert list(G.edges(keys=True, data=True)) == edges
|
||||
|
||||
raise_cases = [dodod2, dodod3, dol]
|
||||
|
||||
@pytest.mark.parametrize("dod", raise_cases)
|
||||
def test_non_multigraph_input_raise(self, dod):
|
||||
# cases where NetworkXError is raised
|
||||
pytest.raises(nx.NetworkXError, self.Graph, dod, multigraph_input=True)
|
||||
pytest.raises(
|
||||
nx.NetworkXError,
|
||||
nx.to_networkx_graph,
|
||||
dod,
|
||||
create_using=self.Graph,
|
||||
multigraph_input=True,
|
||||
)
|
||||
|
||||
def test_getitem(self):
|
||||
G = self.K3
|
||||
assert G[0] == {1: {0: {}}, 2: {0: {}}}
|
||||
with pytest.raises(KeyError):
|
||||
G.__getitem__("j")
|
||||
with pytest.raises(TypeError):
|
||||
G.__getitem__(["A"])
|
||||
|
||||
def test_remove_node(self):
|
||||
G = self.K3
|
||||
G.remove_node(0)
|
||||
assert G.adj == {1: {2: {0: {}}}, 2: {1: {0: {}}}}
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.remove_node(-1)
|
||||
|
||||
def test_add_edge(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(0, 1)
|
||||
assert G.adj == {0: {1: {0: {}}}, 1: {0: {0: {}}}}
|
||||
G = self.Graph()
|
||||
G.add_edge(*(0, 1))
|
||||
assert G.adj == {0: {1: {0: {}}}, 1: {0: {0: {}}}}
|
||||
G = self.Graph()
|
||||
with pytest.raises(ValueError):
|
||||
G.add_edge(None, "anything")
|
||||
|
||||
def test_add_edge_conflicting_key(self):
|
||||
G = self.Graph()
|
||||
G.add_edge(0, 1, key=1)
|
||||
G.add_edge(0, 1)
|
||||
assert G.number_of_edges() == 2
|
||||
G = self.Graph()
|
||||
G.add_edges_from([(0, 1, 1, {})])
|
||||
G.add_edges_from([(0, 1)])
|
||||
assert G.number_of_edges() == 2
|
||||
|
||||
def test_add_edges_from(self):
|
||||
G = self.Graph()
|
||||
G.add_edges_from([(0, 1), (0, 1, {"weight": 3})])
|
||||
assert G.adj == {
|
||||
0: {1: {0: {}, 1: {"weight": 3}}},
|
||||
1: {0: {0: {}, 1: {"weight": 3}}},
|
||||
}
|
||||
G.add_edges_from([(0, 1), (0, 1, {"weight": 3})], weight=2)
|
||||
assert G.adj == {
|
||||
0: {1: {0: {}, 1: {"weight": 3}, 2: {"weight": 2}, 3: {"weight": 3}}},
|
||||
1: {0: {0: {}, 1: {"weight": 3}, 2: {"weight": 2}, 3: {"weight": 3}}},
|
||||
}
|
||||
G = self.Graph()
|
||||
edges = [
|
||||
(0, 1, {"weight": 3}),
|
||||
(0, 1, (("weight", 2),)),
|
||||
(0, 1, 5),
|
||||
(0, 1, "s"),
|
||||
]
|
||||
G.add_edges_from(edges)
|
||||
keydict = {0: {"weight": 3}, 1: {"weight": 2}, 5: {}, "s": {}}
|
||||
assert G._adj == {0: {1: keydict}, 1: {0: keydict}}
|
||||
|
||||
# too few in tuple
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.add_edges_from([(0,)])
|
||||
# too many in tuple
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.add_edges_from([(0, 1, 2, 3, 4)])
|
||||
# not a tuple
|
||||
with pytest.raises(TypeError):
|
||||
G.add_edges_from([0])
|
||||
|
||||
def test_multigraph_add_edges_from_four_tuple_misordered(self):
|
||||
"""add_edges_from expects 4-tuples of the format (u, v, key, data_dict).
|
||||
|
||||
Ensure 4-tuples of form (u, v, data_dict, key) raise exception.
|
||||
"""
|
||||
G = nx.MultiGraph()
|
||||
with pytest.raises(TypeError):
|
||||
# key/data values flipped in 4-tuple
|
||||
G.add_edges_from([(0, 1, {"color": "red"}, 0)])
|
||||
|
||||
def test_remove_edge(self):
|
||||
G = self.K3
|
||||
G.remove_edge(0, 1)
|
||||
assert G.adj == {0: {2: {0: {}}}, 1: {2: {0: {}}}, 2: {0: {0: {}}, 1: {0: {}}}}
|
||||
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.remove_edge(-1, 0)
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.remove_edge(0, 2, key=1)
|
||||
|
||||
def test_remove_edges_from(self):
|
||||
G = self.K3.copy()
|
||||
G.remove_edges_from([(0, 1)])
|
||||
kd = {0: {}}
|
||||
assert G.adj == {0: {2: kd}, 1: {2: kd}, 2: {0: kd, 1: kd}}
|
||||
G.remove_edges_from([(0, 0)]) # silent fail
|
||||
self.K3.add_edge(0, 1)
|
||||
G = self.K3.copy()
|
||||
G.remove_edges_from(list(G.edges(data=True, keys=True)))
|
||||
assert G.adj == {0: {}, 1: {}, 2: {}}
|
||||
G = self.K3.copy()
|
||||
G.remove_edges_from(list(G.edges(data=False, keys=True)))
|
||||
assert G.adj == {0: {}, 1: {}, 2: {}}
|
||||
G = self.K3.copy()
|
||||
G.remove_edges_from(list(G.edges(data=False, keys=False)))
|
||||
assert G.adj == {0: {}, 1: {}, 2: {}}
|
||||
G = self.K3.copy()
|
||||
G.remove_edges_from([(0, 1, 0), (0, 2, 0, {}), (1, 2)])
|
||||
assert G.adj == {0: {1: {1: {}}}, 1: {0: {1: {}}}, 2: {}}
|
||||
|
||||
def test_remove_multiedge(self):
|
||||
G = self.K3
|
||||
G.add_edge(0, 1, key="parallel edge")
|
||||
G.remove_edge(0, 1, key="parallel edge")
|
||||
assert G.adj == {
|
||||
0: {1: {0: {}}, 2: {0: {}}},
|
||||
1: {0: {0: {}}, 2: {0: {}}},
|
||||
2: {0: {0: {}}, 1: {0: {}}},
|
||||
}
|
||||
G.remove_edge(0, 1)
|
||||
kd = {0: {}}
|
||||
assert G.adj == {0: {2: kd}, 1: {2: kd}, 2: {0: kd, 1: kd}}
|
||||
with pytest.raises(nx.NetworkXError):
|
||||
G.remove_edge(-1, 0)
|
||||
|
||||
|
||||
class TestEdgeSubgraph:
|
||||
"""Unit tests for the :meth:`MultiGraph.edge_subgraph` method."""
|
||||
|
||||
def setup_method(self):
|
||||
# Create a doubly-linked path graph on five nodes.
|
||||
G = nx.MultiGraph()
|
||||
nx.add_path(G, range(5))
|
||||
nx.add_path(G, range(5))
|
||||
# Add some node, edge, and graph attributes.
|
||||
for i in range(5):
|
||||
G.nodes[i]["name"] = f"node{i}"
|
||||
G.adj[0][1][0]["name"] = "edge010"
|
||||
G.adj[0][1][1]["name"] = "edge011"
|
||||
G.adj[3][4][0]["name"] = "edge340"
|
||||
G.adj[3][4][1]["name"] = "edge341"
|
||||
G.graph["name"] = "graph"
|
||||
# Get the subgraph induced by one of the first edges and one of
|
||||
# the last edges.
|
||||
self.G = G
|
||||
self.H = G.edge_subgraph([(0, 1, 0), (3, 4, 1)])
|
||||
|
||||
def test_correct_nodes(self):
|
||||
"""Tests that the subgraph has the correct nodes."""
|
||||
assert [0, 1, 3, 4] == sorted(self.H.nodes())
|
||||
|
||||
def test_correct_edges(self):
|
||||
"""Tests that the subgraph has the correct edges."""
|
||||
assert [(0, 1, 0, "edge010"), (3, 4, 1, "edge341")] == sorted(
|
||||
self.H.edges(keys=True, data="name")
|
||||
)
|
||||
|
||||
def test_add_node(self):
|
||||
"""Tests that adding a node to the original graph does not
|
||||
affect the nodes of the subgraph.
|
||||
|
||||
"""
|
||||
self.G.add_node(5)
|
||||
assert [0, 1, 3, 4] == sorted(self.H.nodes())
|
||||
|
||||
def test_remove_node(self):
|
||||
"""Tests that removing a node in the original graph does
|
||||
affect the nodes of the subgraph.
|
||||
|
||||
"""
|
||||
self.G.remove_node(0)
|
||||
assert [1, 3, 4] == sorted(self.H.nodes())
|
||||
|
||||
def test_node_attr_dict(self):
|
||||
"""Tests that the node attribute dictionary of the two graphs is
|
||||
the same object.
|
||||
|
||||
"""
|
||||
for v in self.H:
|
||||
assert self.G.nodes[v] == self.H.nodes[v]
|
||||
# Making a change to G should make a change in H and vice versa.
|
||||
self.G.nodes[0]["name"] = "foo"
|
||||
assert self.G.nodes[0] == self.H.nodes[0]
|
||||
self.H.nodes[1]["name"] = "bar"
|
||||
assert self.G.nodes[1] == self.H.nodes[1]
|
||||
|
||||
def test_edge_attr_dict(self):
|
||||
"""Tests that the edge attribute dictionary of the two graphs is
|
||||
the same object.
|
||||
|
||||
"""
|
||||
for u, v, k in self.H.edges(keys=True):
|
||||
assert self.G._adj[u][v][k] == self.H._adj[u][v][k]
|
||||
# Making a change to G should make a change in H and vice versa.
|
||||
self.G._adj[0][1][0]["name"] = "foo"
|
||||
assert self.G._adj[0][1][0]["name"] == self.H._adj[0][1][0]["name"]
|
||||
self.H._adj[3][4][1]["name"] = "bar"
|
||||
assert self.G._adj[3][4][1]["name"] == self.H._adj[3][4][1]["name"]
|
||||
|
||||
def test_graph_attr_dict(self):
|
||||
"""Tests that the graph attribute dictionary of the two graphs
|
||||
is the same object.
|
||||
|
||||
"""
|
||||
assert self.G.graph is self.H.graph
|
||||
|
||||
|
||||
class CustomDictClass(UserDict):
|
||||
pass
|
||||
|
||||
|
||||
class MultiGraphSubClass(nx.MultiGraph):
|
||||
node_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
node_attr_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
adjlist_outer_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
adjlist_inner_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
edge_key_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
edge_attr_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
graph_attr_dict_factory = CustomDictClass # type: ignore[assignment]
|
||||
|
||||
|
||||
class TestMultiGraphSubclass(TestMultiGraph):
|
||||
def setup_method(self):
|
||||
self.Graph = MultiGraphSubClass
|
||||
# build K3
|
||||
self.k3edges = [(0, 1), (0, 2), (1, 2)]
|
||||
self.k3nodes = [0, 1, 2]
|
||||
self.K3 = self.Graph()
|
||||
self.K3._adj = self.K3.adjlist_outer_dict_factory(
|
||||
{
|
||||
0: self.K3.adjlist_inner_dict_factory(),
|
||||
1: self.K3.adjlist_inner_dict_factory(),
|
||||
2: self.K3.adjlist_inner_dict_factory(),
|
||||
}
|
||||
)
|
||||
self.K3._pred = {0: {}, 1: {}, 2: {}}
|
||||
for u in self.k3nodes:
|
||||
for v in self.k3nodes:
|
||||
if u != v:
|
||||
d = {0: {}}
|
||||
self.K3._adj[u][v] = d
|
||||
self.K3._adj[v][u] = d
|
||||
self.K3._node = self.K3.node_dict_factory()
|
||||
self.K3._node[0] = self.K3.node_attr_dict_factory()
|
||||
self.K3._node[1] = self.K3.node_attr_dict_factory()
|
||||
self.K3._node[2] = self.K3.node_attr_dict_factory()
|
||||
1419
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_reportviews.py
vendored
Normal file
1419
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_reportviews.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
131
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_special.py
vendored
Normal file
131
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_special.py
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
import networkx as nx
|
||||
|
||||
from .test_digraph import BaseDiGraphTester
|
||||
from .test_digraph import TestDiGraph as _TestDiGraph
|
||||
from .test_graph import BaseGraphTester
|
||||
from .test_graph import TestGraph as _TestGraph
|
||||
from .test_multidigraph import TestMultiDiGraph as _TestMultiDiGraph
|
||||
from .test_multigraph import TestMultiGraph as _TestMultiGraph
|
||||
|
||||
|
||||
def test_factories():
|
||||
class mydict1(dict):
|
||||
pass
|
||||
|
||||
class mydict2(dict):
|
||||
pass
|
||||
|
||||
class mydict3(dict):
|
||||
pass
|
||||
|
||||
class mydict4(dict):
|
||||
pass
|
||||
|
||||
class mydict5(dict):
|
||||
pass
|
||||
|
||||
for Graph in (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph):
|
||||
# print("testing class: ", Graph.__name__)
|
||||
class MyGraph(Graph):
|
||||
node_dict_factory = mydict1
|
||||
adjlist_outer_dict_factory = mydict2
|
||||
adjlist_inner_dict_factory = mydict3
|
||||
edge_key_dict_factory = mydict4
|
||||
edge_attr_dict_factory = mydict5
|
||||
|
||||
G = MyGraph()
|
||||
assert isinstance(G._node, mydict1)
|
||||
assert isinstance(G._adj, mydict2)
|
||||
G.add_node(1)
|
||||
assert isinstance(G._adj[1], mydict3)
|
||||
if G.is_directed():
|
||||
assert isinstance(G._pred, mydict2)
|
||||
assert isinstance(G._succ, mydict2)
|
||||
assert isinstance(G._pred[1], mydict3)
|
||||
G.add_edge(1, 2)
|
||||
if G.is_multigraph():
|
||||
assert isinstance(G._adj[1][2], mydict4)
|
||||
assert isinstance(G._adj[1][2][0], mydict5)
|
||||
else:
|
||||
assert isinstance(G._adj[1][2], mydict5)
|
||||
|
||||
|
||||
class TestSpecialGraph(_TestGraph):
|
||||
def setup_method(self):
|
||||
_TestGraph.setup_method(self)
|
||||
self.Graph = nx.Graph
|
||||
|
||||
|
||||
class TestThinGraph(BaseGraphTester):
|
||||
def setup_method(self):
|
||||
all_edge_dict = {"weight": 1}
|
||||
|
||||
class MyGraph(nx.Graph):
|
||||
def edge_attr_dict_factory(self):
|
||||
return all_edge_dict
|
||||
|
||||
self.Graph = MyGraph
|
||||
# build dict-of-dict-of-dict K3
|
||||
ed1, ed2, ed3 = (all_edge_dict, all_edge_dict, all_edge_dict)
|
||||
self.k3adj = {0: {1: ed1, 2: ed2}, 1: {0: ed1, 2: ed3}, 2: {0: ed2, 1: ed3}}
|
||||
self.k3edges = [(0, 1), (0, 2), (1, 2)]
|
||||
self.k3nodes = [0, 1, 2]
|
||||
self.K3 = self.Graph()
|
||||
self.K3._adj = self.k3adj
|
||||
self.K3._node = {}
|
||||
self.K3._node[0] = {}
|
||||
self.K3._node[1] = {}
|
||||
self.K3._node[2] = {}
|
||||
|
||||
|
||||
class TestSpecialDiGraph(_TestDiGraph):
|
||||
def setup_method(self):
|
||||
_TestDiGraph.setup_method(self)
|
||||
self.Graph = nx.DiGraph
|
||||
|
||||
|
||||
class TestThinDiGraph(BaseDiGraphTester):
|
||||
def setup_method(self):
|
||||
all_edge_dict = {"weight": 1}
|
||||
|
||||
class MyGraph(nx.DiGraph):
|
||||
def edge_attr_dict_factory(self):
|
||||
return all_edge_dict
|
||||
|
||||
self.Graph = MyGraph
|
||||
# build dict-of-dict-of-dict K3
|
||||
ed1, ed2, ed3 = (all_edge_dict, all_edge_dict, all_edge_dict)
|
||||
ed4, ed5, ed6 = (all_edge_dict, all_edge_dict, all_edge_dict)
|
||||
self.k3adj = {0: {1: ed1, 2: ed2}, 1: {0: ed3, 2: ed4}, 2: {0: ed5, 1: ed6}}
|
||||
self.k3edges = [(0, 1), (0, 2), (1, 2)]
|
||||
self.k3nodes = [0, 1, 2]
|
||||
self.K3 = self.Graph()
|
||||
self.K3._succ = self.k3adj
|
||||
# K3._adj is synced with K3._succ
|
||||
self.K3._pred = {0: {1: ed3, 2: ed5}, 1: {0: ed1, 2: ed6}, 2: {0: ed2, 1: ed4}}
|
||||
self.K3._node = {}
|
||||
self.K3._node[0] = {}
|
||||
self.K3._node[1] = {}
|
||||
self.K3._node[2] = {}
|
||||
|
||||
ed1, ed2 = (all_edge_dict, all_edge_dict)
|
||||
self.P3 = self.Graph()
|
||||
self.P3._succ = {0: {1: ed1}, 1: {2: ed2}, 2: {}}
|
||||
# P3._adj is synced with P3._succ
|
||||
self.P3._pred = {0: {}, 1: {0: ed1}, 2: {1: ed2}}
|
||||
self.P3._node = {}
|
||||
self.P3._node[0] = {}
|
||||
self.P3._node[1] = {}
|
||||
self.P3._node[2] = {}
|
||||
|
||||
|
||||
class TestSpecialMultiGraph(_TestMultiGraph):
|
||||
def setup_method(self):
|
||||
_TestMultiGraph.setup_method(self)
|
||||
self.Graph = nx.MultiGraph
|
||||
|
||||
|
||||
class TestSpecialMultiDiGraph(_TestMultiDiGraph):
|
||||
def setup_method(self):
|
||||
_TestMultiDiGraph.setup_method(self)
|
||||
self.Graph = nx.MultiDiGraph
|
||||
363
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_subgraphviews.py
vendored
Normal file
363
.CondaPkg/env/Lib/site-packages/networkx/classes/tests/test_subgraphviews.py
vendored
Normal file
@@ -0,0 +1,363 @@
|
||||
import pytest
|
||||
|
||||
import networkx as nx
|
||||
from networkx.utils import edges_equal
|
||||
|
||||
|
||||
class TestSubGraphView:
|
||||
gview = staticmethod(nx.graphviews.subgraph_view)
|
||||
graph = nx.Graph
|
||||
hide_edges_filter = staticmethod(nx.filters.hide_edges)
|
||||
show_edges_filter = staticmethod(nx.filters.show_edges)
|
||||
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.G = nx.path_graph(9, create_using=cls.graph())
|
||||
cls.hide_edges_w_hide_nodes = {(3, 4), (4, 5), (5, 6)}
|
||||
|
||||
def test_hidden_nodes(self):
|
||||
hide_nodes = [4, 5, 111]
|
||||
nodes_gone = nx.filters.hide_nodes(hide_nodes)
|
||||
gview = self.gview
|
||||
print(gview)
|
||||
G = gview(self.G, filter_node=nodes_gone)
|
||||
assert self.G.nodes - G.nodes == {4, 5}
|
||||
assert self.G.edges - G.edges == self.hide_edges_w_hide_nodes
|
||||
if G.is_directed():
|
||||
assert list(G[3]) == []
|
||||
assert list(G[2]) == [3]
|
||||
else:
|
||||
assert list(G[3]) == [2]
|
||||
assert set(G[2]) == {1, 3}
|
||||
pytest.raises(KeyError, G.__getitem__, 4)
|
||||
pytest.raises(KeyError, G.__getitem__, 112)
|
||||
pytest.raises(KeyError, G.__getitem__, 111)
|
||||
assert G.degree(3) == (3 if G.is_multigraph() else 1)
|
||||
assert G.size() == (7 if G.is_multigraph() else 5)
|
||||
|
||||
def test_hidden_edges(self):
|
||||
hide_edges = [(2, 3), (8, 7), (222, 223)]
|
||||
edges_gone = self.hide_edges_filter(hide_edges)
|
||||
gview = self.gview
|
||||
G = gview(self.G, filter_edge=edges_gone)
|
||||
assert self.G.nodes == G.nodes
|
||||
if G.is_directed():
|
||||
assert self.G.edges - G.edges == {(2, 3)}
|
||||
assert list(G[2]) == []
|
||||
assert list(G.pred[3]) == []
|
||||
assert list(G.pred[2]) == [1]
|
||||
assert G.size() == 7
|
||||
else:
|
||||
assert self.G.edges - G.edges == {(2, 3), (7, 8)}
|
||||
assert list(G[2]) == [1]
|
||||
assert G.size() == 6
|
||||
assert list(G[3]) == [4]
|
||||
pytest.raises(KeyError, G.__getitem__, 221)
|
||||
pytest.raises(KeyError, G.__getitem__, 222)
|
||||
assert G.degree(3) == 1
|
||||
|
||||
def test_shown_node(self):
|
||||
induced_subgraph = nx.filters.show_nodes([2, 3, 111])
|
||||
gview = self.gview
|
||||
G = gview(self.G, filter_node=induced_subgraph)
|
||||
assert set(G.nodes) == {2, 3}
|
||||
if G.is_directed():
|
||||
assert list(G[3]) == []
|
||||
else:
|
||||
assert list(G[3]) == [2]
|
||||
assert list(G[2]) == [3]
|
||||
pytest.raises(KeyError, G.__getitem__, 4)
|
||||
pytest.raises(KeyError, G.__getitem__, 112)
|
||||
pytest.raises(KeyError, G.__getitem__, 111)
|
||||
assert G.degree(3) == (3 if G.is_multigraph() else 1)
|
||||
assert G.size() == (3 if G.is_multigraph() else 1)
|
||||
|
||||
def test_shown_edges(self):
|
||||
show_edges = [(2, 3), (8, 7), (222, 223)]
|
||||
edge_subgraph = self.show_edges_filter(show_edges)
|
||||
G = self.gview(self.G, filter_edge=edge_subgraph)
|
||||
assert self.G.nodes == G.nodes
|
||||
if G.is_directed():
|
||||
assert G.edges == {(2, 3)}
|
||||
assert list(G[3]) == []
|
||||
assert list(G[2]) == [3]
|
||||
assert list(G.pred[3]) == [2]
|
||||
assert list(G.pred[2]) == []
|
||||
assert G.size() == 1
|
||||
else:
|
||||
assert G.edges == {(2, 3), (7, 8)}
|
||||
assert list(G[3]) == [2]
|
||||
assert list(G[2]) == [3]
|
||||
assert G.size() == 2
|
||||
pytest.raises(KeyError, G.__getitem__, 221)
|
||||
pytest.raises(KeyError, G.__getitem__, 222)
|
||||
assert G.degree(3) == 1
|
||||
|
||||
|
||||
class TestSubDiGraphView(TestSubGraphView):
|
||||
gview = staticmethod(nx.graphviews.subgraph_view)
|
||||
graph = nx.DiGraph
|
||||
hide_edges_filter = staticmethod(nx.filters.hide_diedges)
|
||||
show_edges_filter = staticmethod(nx.filters.show_diedges)
|
||||
hide_edges = [(2, 3), (8, 7), (222, 223)]
|
||||
excluded = {(2, 3), (3, 4), (4, 5), (5, 6)}
|
||||
|
||||
def test_inoutedges(self):
|
||||
edges_gone = self.hide_edges_filter(self.hide_edges)
|
||||
hide_nodes = [4, 5, 111]
|
||||
nodes_gone = nx.filters.hide_nodes(hide_nodes)
|
||||
G = self.gview(self.G, nodes_gone, edges_gone)
|
||||
|
||||
assert self.G.in_edges - G.in_edges == self.excluded
|
||||
assert self.G.out_edges - G.out_edges == self.excluded
|
||||
|
||||
def test_pred(self):
|
||||
edges_gone = self.hide_edges_filter(self.hide_edges)
|
||||
hide_nodes = [4, 5, 111]
|
||||
nodes_gone = nx.filters.hide_nodes(hide_nodes)
|
||||
G = self.gview(self.G, nodes_gone, edges_gone)
|
||||
|
||||
assert list(G.pred[2]) == [1]
|
||||
assert list(G.pred[6]) == []
|
||||
|
||||
def test_inout_degree(self):
|
||||
edges_gone = self.hide_edges_filter(self.hide_edges)
|
||||
hide_nodes = [4, 5, 111]
|
||||
nodes_gone = nx.filters.hide_nodes(hide_nodes)
|
||||
G = self.gview(self.G, nodes_gone, edges_gone)
|
||||
|
||||
assert G.degree(2) == 1
|
||||
assert G.out_degree(2) == 0
|
||||
assert G.in_degree(2) == 1
|
||||
assert G.size() == 4
|
||||
|
||||
|
||||
# multigraph
|
||||
class TestMultiGraphView(TestSubGraphView):
|
||||
gview = staticmethod(nx.graphviews.subgraph_view)
|
||||
graph = nx.MultiGraph
|
||||
hide_edges_filter = staticmethod(nx.filters.hide_multiedges)
|
||||
show_edges_filter = staticmethod(nx.filters.show_multiedges)
|
||||
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.G = nx.path_graph(9, create_using=cls.graph())
|
||||
multiedges = {(2, 3, 4), (2, 3, 5)}
|
||||
cls.G.add_edges_from(multiedges)
|
||||
cls.hide_edges_w_hide_nodes = {(3, 4, 0), (4, 5, 0), (5, 6, 0)}
|
||||
|
||||
def test_hidden_edges(self):
|
||||
hide_edges = [(2, 3, 4), (2, 3, 3), (8, 7, 0), (222, 223, 0)]
|
||||
edges_gone = self.hide_edges_filter(hide_edges)
|
||||
G = self.gview(self.G, filter_edge=edges_gone)
|
||||
assert self.G.nodes == G.nodes
|
||||
if G.is_directed():
|
||||
assert self.G.edges - G.edges == {(2, 3, 4)}
|
||||
assert list(G[3]) == [4]
|
||||
assert list(G[2]) == [3]
|
||||
assert list(G.pred[3]) == [2] # only one 2 but two edges
|
||||
assert list(G.pred[2]) == [1]
|
||||
assert G.size() == 9
|
||||
else:
|
||||
assert self.G.edges - G.edges == {(2, 3, 4), (7, 8, 0)}
|
||||
assert list(G[3]) == [2, 4]
|
||||
assert list(G[2]) == [1, 3]
|
||||
assert G.size() == 8
|
||||
assert G.degree(3) == 3
|
||||
pytest.raises(KeyError, G.__getitem__, 221)
|
||||
pytest.raises(KeyError, G.__getitem__, 222)
|
||||
|
||||
def test_shown_edges(self):
|
||||
show_edges = [(2, 3, 4), (2, 3, 3), (8, 7, 0), (222, 223, 0)]
|
||||
edge_subgraph = self.show_edges_filter(show_edges)
|
||||
G = self.gview(self.G, filter_edge=edge_subgraph)
|
||||
assert self.G.nodes == G.nodes
|
||||
if G.is_directed():
|
||||
assert G.edges == {(2, 3, 4)}
|
||||
assert list(G[3]) == []
|
||||
assert list(G.pred[3]) == [2]
|
||||
assert list(G.pred[2]) == []
|
||||
assert G.size() == 1
|
||||
else:
|
||||
assert G.edges == {(2, 3, 4), (7, 8, 0)}
|
||||
assert G.size() == 2
|
||||
assert list(G[3]) == [2]
|
||||
assert G.degree(3) == 1
|
||||
assert list(G[2]) == [3]
|
||||
pytest.raises(KeyError, G.__getitem__, 221)
|
||||
pytest.raises(KeyError, G.__getitem__, 222)
|
||||
|
||||
|
||||
# multidigraph
|
||||
class TestMultiDiGraphView(TestMultiGraphView, TestSubDiGraphView):
|
||||
gview = staticmethod(nx.graphviews.subgraph_view)
|
||||
graph = nx.MultiDiGraph
|
||||
hide_edges_filter = staticmethod(nx.filters.hide_multidiedges)
|
||||
show_edges_filter = staticmethod(nx.filters.show_multidiedges)
|
||||
hide_edges = [(2, 3, 0), (8, 7, 0), (222, 223, 0)]
|
||||
excluded = {(2, 3, 0), (3, 4, 0), (4, 5, 0), (5, 6, 0)}
|
||||
|
||||
def test_inout_degree(self):
|
||||
edges_gone = self.hide_edges_filter(self.hide_edges)
|
||||
hide_nodes = [4, 5, 111]
|
||||
nodes_gone = nx.filters.hide_nodes(hide_nodes)
|
||||
G = self.gview(self.G, nodes_gone, edges_gone)
|
||||
|
||||
assert G.degree(2) == 3
|
||||
assert G.out_degree(2) == 2
|
||||
assert G.in_degree(2) == 1
|
||||
assert G.size() == 6
|
||||
|
||||
|
||||
# induced_subgraph
|
||||
class TestInducedSubGraph:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.K3 = G = nx.complete_graph(3)
|
||||
G.graph["foo"] = []
|
||||
G.nodes[0]["foo"] = []
|
||||
G.remove_edge(1, 2)
|
||||
ll = []
|
||||
G.add_edge(1, 2, foo=ll)
|
||||
G.add_edge(2, 1, foo=ll)
|
||||
|
||||
def test_full_graph(self):
|
||||
G = self.K3
|
||||
H = nx.induced_subgraph(G, [0, 1, 2, 5])
|
||||
assert H.name == G.name
|
||||
self.graphs_equal(H, G)
|
||||
self.same_attrdict(H, G)
|
||||
|
||||
def test_partial_subgraph(self):
|
||||
G = self.K3
|
||||
H = nx.induced_subgraph(G, 0)
|
||||
assert dict(H.adj) == {0: {}}
|
||||
assert dict(G.adj) != {0: {}}
|
||||
|
||||
H = nx.induced_subgraph(G, [0, 1])
|
||||
assert dict(H.adj) == {0: {1: {}}, 1: {0: {}}}
|
||||
|
||||
def same_attrdict(self, H, G):
|
||||
old_foo = H[1][2]["foo"]
|
||||
H.edges[1, 2]["foo"] = "baz"
|
||||
assert G.edges == H.edges
|
||||
H.edges[1, 2]["foo"] = old_foo
|
||||
assert G.edges == H.edges
|
||||
old_foo = H.nodes[0]["foo"]
|
||||
H.nodes[0]["foo"] = "baz"
|
||||
assert G.nodes == H.nodes
|
||||
H.nodes[0]["foo"] = old_foo
|
||||
assert G.nodes == H.nodes
|
||||
|
||||
def graphs_equal(self, H, G):
|
||||
assert G._adj == H._adj
|
||||
assert G._node == H._node
|
||||
assert G.graph == H.graph
|
||||
assert G.name == H.name
|
||||
if not G.is_directed() and not H.is_directed():
|
||||
assert H._adj[1][2] is H._adj[2][1]
|
||||
assert G._adj[1][2] is G._adj[2][1]
|
||||
else: # at least one is directed
|
||||
if not G.is_directed():
|
||||
G._pred = G._adj
|
||||
G._succ = G._adj
|
||||
if not H.is_directed():
|
||||
H._pred = H._adj
|
||||
H._succ = H._adj
|
||||
assert G._pred == H._pred
|
||||
assert G._succ == H._succ
|
||||
assert H._succ[1][2] is H._pred[2][1]
|
||||
assert G._succ[1][2] is G._pred[2][1]
|
||||
|
||||
|
||||
# edge_subgraph
|
||||
class TestEdgeSubGraph:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
# Create a path graph on five nodes.
|
||||
cls.G = G = nx.path_graph(5)
|
||||
# Add some node, edge, and graph attributes.
|
||||
for i in range(5):
|
||||
G.nodes[i]["name"] = f"node{i}"
|
||||
G.edges[0, 1]["name"] = "edge01"
|
||||
G.edges[3, 4]["name"] = "edge34"
|
||||
G.graph["name"] = "graph"
|
||||
# Get the subgraph induced by the first and last edges.
|
||||
cls.H = nx.edge_subgraph(G, [(0, 1), (3, 4)])
|
||||
|
||||
def test_correct_nodes(self):
|
||||
"""Tests that the subgraph has the correct nodes."""
|
||||
assert [(0, "node0"), (1, "node1"), (3, "node3"), (4, "node4")] == sorted(
|
||||
self.H.nodes.data("name")
|
||||
)
|
||||
|
||||
def test_correct_edges(self):
|
||||
"""Tests that the subgraph has the correct edges."""
|
||||
assert edges_equal(
|
||||
[(0, 1, "edge01"), (3, 4, "edge34")], self.H.edges.data("name")
|
||||
)
|
||||
|
||||
def test_add_node(self):
|
||||
"""Tests that adding a node to the original graph does not
|
||||
affect the nodes of the subgraph.
|
||||
|
||||
"""
|
||||
self.G.add_node(5)
|
||||
assert [0, 1, 3, 4] == sorted(self.H.nodes)
|
||||
self.G.remove_node(5)
|
||||
|
||||
def test_remove_node(self):
|
||||
"""Tests that removing a node in the original graph
|
||||
removes the nodes of the subgraph.
|
||||
|
||||
"""
|
||||
self.G.remove_node(0)
|
||||
assert [1, 3, 4] == sorted(self.H.nodes)
|
||||
self.G.add_node(0, name="node0")
|
||||
self.G.add_edge(0, 1, name="edge01")
|
||||
|
||||
def test_node_attr_dict(self):
|
||||
"""Tests that the node attribute dictionary of the two graphs is
|
||||
the same object.
|
||||
|
||||
"""
|
||||
for v in self.H:
|
||||
assert self.G.nodes[v] == self.H.nodes[v]
|
||||
# Making a change to G should make a change in H and vice versa.
|
||||
self.G.nodes[0]["name"] = "foo"
|
||||
assert self.G.nodes[0] == self.H.nodes[0]
|
||||
self.H.nodes[1]["name"] = "bar"
|
||||
assert self.G.nodes[1] == self.H.nodes[1]
|
||||
# Revert the change, so tests pass with pytest-randomly
|
||||
self.G.nodes[0]["name"] = "node0"
|
||||
self.H.nodes[1]["name"] = "node1"
|
||||
|
||||
def test_edge_attr_dict(self):
|
||||
"""Tests that the edge attribute dictionary of the two graphs is
|
||||
the same object.
|
||||
|
||||
"""
|
||||
for u, v in self.H.edges():
|
||||
assert self.G.edges[u, v] == self.H.edges[u, v]
|
||||
# Making a change to G should make a change in H and vice versa.
|
||||
self.G.edges[0, 1]["name"] = "foo"
|
||||
assert self.G.edges[0, 1]["name"] == self.H.edges[0, 1]["name"]
|
||||
self.H.edges[3, 4]["name"] = "bar"
|
||||
assert self.G.edges[3, 4]["name"] == self.H.edges[3, 4]["name"]
|
||||
# Revert the change, so tests pass with pytest-randomly
|
||||
self.G.edges[0, 1]["name"] = "edge01"
|
||||
self.H.edges[3, 4]["name"] = "edge34"
|
||||
|
||||
def test_graph_attr_dict(self):
|
||||
"""Tests that the graph attribute dictionary of the two graphs
|
||||
is the same object.
|
||||
|
||||
"""
|
||||
assert self.G.graph is self.H.graph
|
||||
|
||||
def test_readonly(self):
|
||||
"""Tests that the subgraph cannot change the graph structure"""
|
||||
pytest.raises(nx.NetworkXError, self.H.add_node, 5)
|
||||
pytest.raises(nx.NetworkXError, self.H.remove_node, 0)
|
||||
pytest.raises(nx.NetworkXError, self.H.add_edge, 5, 6)
|
||||
pytest.raises(nx.NetworkXError, self.H.remove_edge, 0, 1)
|
||||
Reference in New Issue
Block a user