| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- """
- Testing
- =======
- General guidelines for writing good tests:
- - doctests always assume ``import networkx as nx`` so don't add that
- - prefer pytest fixtures over classes with setup methods.
- - use the ``@pytest.mark.parametrize`` decorator
- - use ``pytest.importorskip`` for numpy, scipy, pandas, and matplotlib b/c of PyPy.
- and add the module to the relevant entries below.
- """
- import os
- import warnings
- from importlib.metadata import entry_points
- import pytest
- import networkx as nx
- def pytest_addoption(parser):
- parser.addoption(
- "--runslow", action="store_true", default=False, help="run slow tests"
- )
- parser.addoption(
- "--backend",
- action="store",
- default=None,
- help="Run tests with a backend by auto-converting nx graphs to backend graphs",
- )
- parser.addoption(
- "--fallback-to-nx",
- action="store_true",
- default=False,
- help="Run nx function if a backend doesn't implement a dispatchable function"
- " (use with --backend)",
- )
- def pytest_configure(config):
- config.addinivalue_line("markers", "slow: mark test as slow to run")
- backend = config.getoption("--backend")
- if backend is None:
- backend = os.environ.get("NETWORKX_TEST_BACKEND")
- # nx_loopback backend is only available when testing with a backend
- loopback_ep = entry_points(name="nx_loopback", group="networkx.backends")
- if not loopback_ep:
- warnings.warn(
- "\n\n WARNING: Mixed NetworkX configuration! \n\n"
- " This environment has mixed configuration for networkx.\n"
- " The test object nx_loopback is not configured correctly.\n"
- " You should not be seeing this message.\n"
- " Try `pip install -e .`, or change your PYTHONPATH\n"
- " Make sure python finds the networkx repo you are testing\n\n"
- )
- config.backend = backend
- if backend:
- # We will update `networkx.config.backend_priority` below in `*_modify_items`
- # to allow tests to get set up with normal networkx graphs.
- nx.utils.backends.backends["nx_loopback"] = loopback_ep["nx_loopback"]
- nx.utils.backends.backend_info["nx_loopback"] = {}
- nx.config.backends = nx.utils.Config(
- nx_loopback=nx.utils.Config(),
- **nx.config.backends,
- )
- fallback_to_nx = config.getoption("--fallback-to-nx")
- if not fallback_to_nx:
- fallback_to_nx = os.environ.get("NETWORKX_FALLBACK_TO_NX")
- nx.config.fallback_to_nx = bool(fallback_to_nx)
- nx.utils.backends._dispatchable.__call__ = (
- nx.utils.backends._dispatchable._call_if_any_backends_installed
- )
- def pytest_collection_modifyitems(config, items):
- # Setting this to True here allows tests to be set up before dispatching
- # any function call to a backend.
- if config.backend:
- # Allow pluggable backends to add markers to tests (such as skip or xfail)
- # when running in auto-conversion test mode
- backend_name = config.backend
- if backend_name != "networkx":
- nx.utils.backends._dispatchable._is_testing = True
- nx.config.backend_priority.algos = [backend_name]
- nx.config.backend_priority.generators = [backend_name]
- backend = nx.utils.backends.backends[backend_name].load()
- if hasattr(backend, "on_start_tests"):
- getattr(backend, "on_start_tests")(items)
- if config.getoption("--runslow"):
- # --runslow given in cli: do not skip slow tests
- return
- skip_slow = pytest.mark.skip(reason="need --runslow option to run")
- for item in items:
- if "slow" in item.keywords:
- item.add_marker(skip_slow)
- # TODO: The warnings below need to be dealt with, but for now we silence them.
- @pytest.fixture(autouse=True)
- def set_warnings():
- warnings.filterwarnings(
- "ignore",
- category=UserWarning,
- message=r"Exited (at iteration \d+|postprocessing) with accuracies.*",
- )
- warnings.filterwarnings(
- "ignore",
- category=UserWarning,
- message=r"The hashes produced for ",
- )
- warnings.filterwarnings(
- "ignore", category=DeprecationWarning, message="\n\nThe `normalized`"
- )
- warnings.filterwarnings(
- "ignore", category=DeprecationWarning, message="maybe_regular_expander"
- )
- warnings.filterwarnings(
- "ignore", category=DeprecationWarning, message="metric_closure is deprecated"
- )
- @pytest.fixture(autouse=True)
- def add_nx(doctest_namespace):
- doctest_namespace["nx"] = nx
- # What dependencies are installed?
- try:
- import numpy as np
- has_numpy = True
- except ImportError:
- has_numpy = False
- try:
- import scipy as sp
- has_scipy = True
- except ImportError:
- has_scipy = False
- try:
- import matplotlib as mpl
- has_matplotlib = True
- except ImportError:
- has_matplotlib = False
- try:
- import pandas as pd
- has_pandas = True
- except ImportError:
- has_pandas = False
- try:
- import pygraphviz
- has_pygraphviz = True
- except ImportError:
- has_pygraphviz = False
- try:
- import pydot
- has_pydot = True
- except ImportError:
- has_pydot = False
- try:
- import sympy
- has_sympy = True
- except ImportError:
- has_sympy = False
- # List of files that pytest should ignore
- collect_ignore = []
- needs_numpy = [
- "algorithms/approximation/traveling_salesman.py",
- "algorithms/centrality/current_flow_closeness.py",
- "algorithms/centrality/laplacian.py",
- "algorithms/node_classification.py",
- "algorithms/non_randomness.py",
- "algorithms/polynomials.py",
- "algorithms/shortest_paths/dense.py",
- "algorithms/tree/mst.py",
- "drawing/nx_latex.py",
- "generators/expanders.py",
- "linalg/bethehessianmatrix.py",
- "linalg/laplacianmatrix.py",
- "utils/misc.py",
- ]
- needs_scipy = [
- "algorithms/approximation/traveling_salesman.py",
- "algorithms/assortativity/correlation.py",
- "algorithms/assortativity/mixing.py",
- "algorithms/assortativity/pairs.py",
- "algorithms/bipartite/matrix.py",
- "algorithms/bipartite/spectral.py",
- "algorithms/bipartite/link_analysis.py",
- "algorithms/centrality/current_flow_betweenness.py",
- "algorithms/centrality/current_flow_betweenness_subset.py",
- "algorithms/centrality/eigenvector.py",
- "algorithms/centrality/katz.py",
- "algorithms/centrality/laplacian.py",
- "algorithms/centrality/second_order.py",
- "algorithms/centrality/subgraph_alg.py",
- "algorithms/communicability_alg.py",
- "algorithms/community/divisive.py",
- "algorithms/community/bipartitions.py",
- "algorithms/distance_measures.py",
- "algorithms/link_analysis/hits_alg.py",
- "algorithms/link_analysis/pagerank_alg.py",
- "algorithms/node_classification.py",
- "algorithms/similarity.py",
- "algorithms/tree/mst.py",
- "algorithms/walks.py",
- "convert_matrix.py",
- "drawing/layout.py",
- "drawing/nx_pylab.py",
- "generators/spectral_graph_forge.py",
- "generators/geometric.py",
- "generators/expanders.py",
- "linalg/algebraicconnectivity.py",
- "linalg/attrmatrix.py",
- "linalg/bethehessianmatrix.py",
- "linalg/graphmatrix.py",
- "linalg/laplacianmatrix.py",
- "linalg/modularitymatrix.py",
- "linalg/spectrum.py",
- "utils/rcm.py",
- ]
- needs_matplotlib = ["drawing/nx_pylab.py", "generators/classic.py"]
- needs_pandas = ["convert_matrix.py"]
- needs_pygraphviz = ["drawing/nx_agraph.py"]
- needs_pydot = ["drawing/nx_pydot.py"]
- needs_sympy = ["algorithms/polynomials.py"]
- if not has_numpy:
- collect_ignore += needs_numpy
- if not has_scipy:
- collect_ignore += needs_scipy
- if not has_matplotlib:
- collect_ignore += needs_matplotlib
- if not has_pandas:
- collect_ignore += needs_pandas
- if not has_pygraphviz:
- collect_ignore += needs_pygraphviz
- if not has_pydot:
- collect_ignore += needs_pydot
- if not has_sympy:
- collect_ignore += needs_sympy
|