diff options
author | Ross Barnowski <rossbar@berkeley.edu> | 2021-11-17 21:12:56 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-17 21:12:56 -0800 |
commit | 00c261f951ae6734001e0419d2bc754eef6dd1b2 (patch) | |
tree | 54e6ce86c89f3de9f2d960f4726025487216d3c8 | |
parent | 4ebdb5e2ca6c6a1f9fb3bf8c2279f9b857c6d8a7 (diff) | |
download | networkx-00c261f951ae6734001e0419d2bc754eef6dd1b2.tar.gz |
Add Mypy type checking infrastructure (#5127)
* Add minimal mypy configuration file.
* Add mypy workflow to GH.
* Properly import sentinels from traversal.edgedfs.
* mypy doesn't like variables named \"e\".
* Rm annotations from single function.
* Fix name collisions in test suite.
Make sure all tests have unique names.
* Rm unused random seed in test setup.
* Rm redundant __all__ specification.
* Silence mypy error from sum(). Mypy bug?
* Fix tsp test instantiation nit.
* \"type: ignore\" to suppress conditional fn sigature errors.
* Remaining \"type: ignore\" to appease mypy.
* Configure mypy to ignore inheritance issues.
* Update exclude conf for CI.
- Add yaml
- Reformat regex containing reportviews
* Rm partial annotations from lukes.py.
Fixes mypy errors due to unannotated code.
* Reorg defaultdict to reduce type: ignore cruft.
* Homogenize signatures for fns defined in conditionals.
* err as varname only in exception catching.
* Fix name collision in Bellman-Ford test suite.
25 files changed, 173 insertions, 166 deletions
diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml new file mode 100644 index 00000000..4fb47ba8 --- /dev/null +++ b/.github/workflows/mypy.yml @@ -0,0 +1,30 @@ +name: Mypy + +on: [push, pull_request] + +jobs: + type-check: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.9] + + steps: + - uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install packages + run: | + pip install --upgrade pip wheel setuptools + pip install -r requirements/developer.txt + # Rm below when yaml no longer a dep + pip install types-PyYAML + pip install -e . + pip list + + - name: run mypy + run: mypy -p networkx diff --git a/.mypy.ini b/.mypy.ini new file mode 100644 index 00000000..f10a25b3 --- /dev/null +++ b/.mypy.ini @@ -0,0 +1,3 @@ +[mypy] +ignore_missing_imports = True +exclude = yaml|subgraphviews|reportviews* diff --git a/networkx/algorithms/approximation/kcomponents.py b/networkx/algorithms/approximation/kcomponents.py index 12048da1..518a0274 100644 --- a/networkx/algorithms/approximation/kcomponents.py +++ b/networkx/algorithms/approximation/kcomponents.py @@ -213,7 +213,7 @@ class _AntiGraph(nx.Graph): def single_edge_dict(self): return self.all_edge_dict - edge_attr_dict_factory = single_edge_dict + edge_attr_dict_factory = single_edge_dict # type: ignore def __getitem__(self, n): """Returns a dict of neighbors of node n in the dense graph. diff --git a/networkx/algorithms/approximation/tests/test_traveling_salesman.py b/networkx/algorithms/approximation/tests/test_traveling_salesman.py index 56574f63..50d02b6c 100644 --- a/networkx/algorithms/approximation/tests/test_traveling_salesman.py +++ b/networkx/algorithms/approximation/tests/test_traveling_salesman.py @@ -39,83 +39,84 @@ def test_christofides_ignore_selfloops(): # set up graphs for other tests -@classmethod -def _setup_class(cls): - cls.DG = nx.DiGraph() - cls.DG.add_weighted_edges_from( - { - ("A", "B", 3), - ("A", "C", 17), - ("A", "D", 14), - ("B", "A", 3), - ("B", "C", 12), - ("B", "D", 16), - ("C", "A", 13), - ("C", "B", 12), - ("C", "D", 4), - ("D", "A", 14), - ("D", "B", 15), - ("D", "C", 2), - } - ) - cls.DG_cycle = ["D", "C", "B", "A", "D"] - cls.DG_cost = 31.0 - - cls.DG2 = nx.DiGraph() - cls.DG2.add_weighted_edges_from( - { - ("A", "B", 3), - ("A", "C", 17), - ("A", "D", 14), - ("B", "A", 30), - ("B", "C", 2), - ("B", "D", 16), - ("C", "A", 33), - ("C", "B", 32), - ("C", "D", 34), - ("D", "A", 14), - ("D", "B", 15), - ("D", "C", 2), - } - ) - cls.DG2_cycle = ["D", "A", "B", "C", "D"] - cls.DG2_cost = 53.0 - - cls.unweightedUG = nx.complete_graph(5, nx.Graph()) - cls.unweightedDG = nx.complete_graph(5, nx.DiGraph()) - - cls.incompleteUG = nx.Graph() - cls.incompleteUG.add_weighted_edges_from({(0, 1, 1), (1, 2, 3)}) - cls.incompleteDG = nx.DiGraph() - cls.incompleteDG.add_weighted_edges_from({(0, 1, 1), (1, 2, 3)}) - - cls.UG = nx.Graph() - cls.UG.add_weighted_edges_from( - { - ("A", "B", 3), - ("A", "C", 17), - ("A", "D", 14), - ("B", "C", 12), - ("B", "D", 16), - ("C", "D", 4), - } - ) - cls.UG_cycle = ["D", "C", "B", "A", "D"] - cls.UG_cost = 33.0 - - cls.UG2 = nx.Graph() - cls.UG2.add_weighted_edges_from( - { - ("A", "B", 1), - ("A", "C", 15), - ("A", "D", 5), - ("B", "C", 16), - ("B", "D", 8), - ("C", "D", 3), - } - ) - cls.UG2_cycle = ["D", "C", "B", "A", "D"] - cls.UG2_cost = 25.0 +class TestBase: + @classmethod + def setup_class(cls): + cls.DG = nx.DiGraph() + cls.DG.add_weighted_edges_from( + { + ("A", "B", 3), + ("A", "C", 17), + ("A", "D", 14), + ("B", "A", 3), + ("B", "C", 12), + ("B", "D", 16), + ("C", "A", 13), + ("C", "B", 12), + ("C", "D", 4), + ("D", "A", 14), + ("D", "B", 15), + ("D", "C", 2), + } + ) + cls.DG_cycle = ["D", "C", "B", "A", "D"] + cls.DG_cost = 31.0 + + cls.DG2 = nx.DiGraph() + cls.DG2.add_weighted_edges_from( + { + ("A", "B", 3), + ("A", "C", 17), + ("A", "D", 14), + ("B", "A", 30), + ("B", "C", 2), + ("B", "D", 16), + ("C", "A", 33), + ("C", "B", 32), + ("C", "D", 34), + ("D", "A", 14), + ("D", "B", 15), + ("D", "C", 2), + } + ) + cls.DG2_cycle = ["D", "A", "B", "C", "D"] + cls.DG2_cost = 53.0 + + cls.unweightedUG = nx.complete_graph(5, nx.Graph()) + cls.unweightedDG = nx.complete_graph(5, nx.DiGraph()) + + cls.incompleteUG = nx.Graph() + cls.incompleteUG.add_weighted_edges_from({(0, 1, 1), (1, 2, 3)}) + cls.incompleteDG = nx.DiGraph() + cls.incompleteDG.add_weighted_edges_from({(0, 1, 1), (1, 2, 3)}) + + cls.UG = nx.Graph() + cls.UG.add_weighted_edges_from( + { + ("A", "B", 3), + ("A", "C", 17), + ("A", "D", 14), + ("B", "C", 12), + ("B", "D", 16), + ("C", "D", 4), + } + ) + cls.UG_cycle = ["D", "C", "B", "A", "D"] + cls.UG_cost = 33.0 + + cls.UG2 = nx.Graph() + cls.UG2.add_weighted_edges_from( + { + ("A", "B", 1), + ("A", "C", 15), + ("A", "D", 5), + ("B", "C", 16), + ("B", "D", 8), + ("C", "D", 3), + } + ) + cls.UG2_cycle = ["D", "C", "B", "A", "D"] + cls.UG2_cost = 25.0 def validate_solution(soln, cost, exp_soln, exp_cost): @@ -128,9 +129,7 @@ def validate_symmetric_solution(soln, cost, exp_soln, exp_cost): assert cost == exp_cost -class TestGreedyTSP: - setup_class = _setup_class - +class TestGreedyTSP(TestBase): def test_greedy(self): cycle = nx_app.greedy_tsp(self.DG, source="D") cost = sum(self.DG[n][nbr]["weight"] for n, nbr in pairwise(cycle)) @@ -170,8 +169,7 @@ class TestGreedyTSP: assert len(cycle) - 1 == len(G) == len(set(cycle)) -class TestSimulatedAnnealingTSP: - setup_class = _setup_class +class TestSimulatedAnnealingTSP(TestBase): tsp = staticmethod(nx_app.simulated_annealing_tsp) def test_simulated_annealing_directed(self): diff --git a/networkx/algorithms/bipartite/edgelist.py b/networkx/algorithms/bipartite/edgelist.py index 77645d20..356f4ab7 100644 --- a/networkx/algorithms/bipartite/edgelist.py +++ b/networkx/algorithms/bipartite/edgelist.py @@ -133,17 +133,17 @@ def generate_edgelist(G, delimiter=" ", data=True): raise AttributeError("Missing node attribute `bipartite`") from err if data is True or data is False: for n in part0: - for e in G.edges(n, data=data): - yield delimiter.join(map(str, e)) + for edge in G.edges(n, data=data): + yield delimiter.join(map(str, edge)) else: for n in part0: for u, v, d in G.edges(n, data=True): - e = [u, v] + edge = [u, v] try: - e.extend(d[k] for k in data) + edge.extend(d[k] for k in data) except KeyError: pass # missing data for this edge, should warn? - yield delimiter.join(map(str, e)) + yield delimiter.join(map(str, edge)) def parse_edgelist( diff --git a/networkx/algorithms/centrality/katz.py b/networkx/algorithms/centrality/katz.py index 523dce04..236f2c61 100644 --- a/networkx/algorithms/centrality/katz.py +++ b/networkx/algorithms/centrality/katz.py @@ -176,8 +176,8 @@ def katz_centrality( x[n] = alpha * x[n] + b[n] # check convergence - err = sum(abs(x[n] - xlast[n]) for n in x) - if err < nnodes * tol: + error = sum(abs(x[n] - xlast[n]) for n in x) + if error < nnodes * tol: if normalized: # normalize vector try: diff --git a/networkx/algorithms/community/lukes.py b/networkx/algorithms/community/lukes.py index 6fe1d0de..b34077a2 100644 --- a/networkx/algorithms/community/lukes.py +++ b/networkx/algorithms/community/lukes.py @@ -17,7 +17,7 @@ PKEY = "partitions" CLUSTER_EVAL_CACHE_SIZE = 2048 -def _split_n_from(n: int, min_size_of_first_part: int): +def _split_n_from(n, min_size_of_first_part): # splits j in two parts of which the first is at least # the second argument assert n >= min_size_of_first_part @@ -25,7 +25,7 @@ def _split_n_from(n: int, min_size_of_first_part: int): yield p1, n - p1 -def lukes_partitioning(G, max_size: int, node_weight=None, edge_weight=None) -> list: +def lukes_partitioning(G, max_size, node_weight=None, edge_weight=None): """Optimal partitioning of a weighted tree using the Lukes algorithm. @@ -130,23 +130,23 @@ def lukes_partitioning(G, max_size: int, node_weight=None, edge_weight=None) -> return n @lru_cache(CLUSTER_EVAL_CACHE_SIZE) - def _value_of_cluster(cluster: frozenset): + def _value_of_cluster(cluster): valid_edges = [e for e in safe_G.edges if e[0] in cluster and e[1] in cluster] return sum(safe_G.edges[e][edge_weight] for e in valid_edges) - def _value_of_partition(partition: list): + def _value_of_partition(partition): return sum(_value_of_cluster(frozenset(c)) for c in partition) @lru_cache(CLUSTER_EVAL_CACHE_SIZE) - def _weight_of_cluster(cluster: frozenset): + def _weight_of_cluster(cluster): return sum(safe_G.nodes[n][node_weight] for n in cluster) - def _pivot(partition: list, node): + def _pivot(partition, node): ccx = [c for c in partition if node in c] assert len(ccx) == 1 return ccx[0] - def _concatenate_or_merge(partition_1: list, partition_2: list, x, i, ref_weigth): + def _concatenate_or_merge(partition_1, partition_2, x, i, ref_weigth): ccx = _pivot(partition_1, x) cci = _pivot(partition_2, i) diff --git a/networkx/algorithms/connectivity/__init__.py b/networkx/algorithms/connectivity/__init__.py index 65490c00..15bc5abe 100644 --- a/networkx/algorithms/connectivity/__init__.py +++ b/networkx/algorithms/connectivity/__init__.py @@ -9,18 +9,3 @@ from .kcomponents import * from .kcutsets import * from .stoerwagner import * from .utils import * - -__all__ = sum( - [ - connectivity.__all__, - cuts.__all__, - edge_augmentation.__all__, - edge_kcomponents.__all__, - disjoint_paths.__all__, - kcomponents.__all__, - kcutsets.__all__, - stoerwagner.__all__, - utils.__all__, - ], - [], -) diff --git a/networkx/algorithms/d_separation.py b/networkx/algorithms/d_separation.py index 9d41e2d8..29f1b7cd 100644 --- a/networkx/algorithms/d_separation.py +++ b/networkx/algorithms/d_separation.py @@ -67,7 +67,7 @@ __all__ = ["d_separated"] @not_implemented_for("undirected") -def d_separated(G: nx.DiGraph, x: AbstractSet, y: AbstractSet, z: AbstractSet) -> bool: +def d_separated(G, x, y, z): """ Return whether node sets ``x`` and ``y`` are d-separated by ``z``. diff --git a/networkx/algorithms/flow/tests/test_maxflow.py b/networkx/algorithms/flow/tests/test_maxflow.py index 17b82b4d..9bb69198 100644 --- a/networkx/algorithms/flow/tests/test_maxflow.py +++ b/networkx/algorithms/flow/tests/test_maxflow.py @@ -19,7 +19,7 @@ flow_funcs = [ ] max_min_funcs = [nx.maximum_flow, nx.minimum_cut] flow_value_funcs = [nx.maximum_flow_value, nx.minimum_cut_value] -interface_funcs = sum([max_min_funcs, flow_value_funcs], []) +interface_funcs = max_min_funcs + flow_value_funcs all_funcs = sum([flow_funcs, interface_funcs], []) diff --git a/networkx/algorithms/shortest_paths/tests/test_weighted.py b/networkx/algorithms/shortest_paths/tests/test_weighted.py index 032b189d..15a219ee 100644 --- a/networkx/algorithms/shortest_paths/tests/test_weighted.py +++ b/networkx/algorithms/shortest_paths/tests/test_weighted.py @@ -838,7 +838,7 @@ class TestBellmanFordAndGoldbergRadzik(WeightedTestBase): assert pred[3] == 0 assert dist == {0: 0, 1: 1, 2: 2, 3: 1} - def test_negative_weight(self): + def test_negative_weight_bf_path(self): G = nx.DiGraph() G.add_nodes_from("abcd") G.add_edge("a", "d", weight=0) diff --git a/networkx/algorithms/tests/test_cycles.py b/networkx/algorithms/tests/test_cycles.py index d509e41c..737d29f4 100644 --- a/networkx/algorithms/tests/test_cycles.py +++ b/networkx/algorithms/tests/test_cycles.py @@ -4,9 +4,7 @@ import networkx as nx from networkx.algorithms import find_cycle from networkx.algorithms import minimum_cycle_basis - -FORWARD = nx.algorithms.edgedfs.FORWARD -REVERSE = nx.algorithms.edgedfs.REVERSE +from networkx.algorithms.traversal.edgedfs import FORWARD, REVERSE class TestCycles: diff --git a/networkx/algorithms/tests/test_graph_hashing.py b/networkx/algorithms/tests/test_graph_hashing.py index 70130b39..c76a66e1 100644 --- a/networkx/algorithms/tests/test_graph_hashing.py +++ b/networkx/algorithms/tests/test_graph_hashing.py @@ -455,7 +455,7 @@ def test_missing_node_attr_subgraph_hash(): ) -def test_isomorphic_edge_attr_and_node_attr(): +def test_isomorphic_edge_attr_and_node_attr_subgraph_hash(): """ Isomorphic graphs with differing node attributes should yield different subgraph hashes if the 'node_attr' and 'edge_attr' argument is supplied and populated in diff --git a/networkx/algorithms/tests/test_smallworld.py b/networkx/algorithms/tests/test_smallworld.py index b6219133..e56f9a6a 100644 --- a/networkx/algorithms/tests/test_smallworld.py +++ b/networkx/algorithms/tests/test_smallworld.py @@ -7,7 +7,6 @@ import random from networkx import random_reference, lattice_reference, sigma, omega import networkx as nx -rng = random.Random(0) rng = 42 diff --git a/networkx/algorithms/traversal/tests/test_edgebfs.py b/networkx/algorithms/traversal/tests/test_edgebfs.py index 170be25c..1bf3fae0 100644 --- a/networkx/algorithms/traversal/tests/test_edgebfs.py +++ b/networkx/algorithms/traversal/tests/test_edgebfs.py @@ -1,11 +1,7 @@ import pytest import networkx as nx - -edge_bfs = nx.edge_bfs - -FORWARD = nx.algorithms.edgedfs.FORWARD -REVERSE = nx.algorithms.edgedfs.REVERSE +from networkx.algorithms.traversal.edgedfs import FORWARD, REVERSE class TestEdgeBFS: @@ -16,42 +12,42 @@ class TestEdgeBFS: def test_empty(self): G = nx.Graph() - edges = list(edge_bfs(G)) + edges = list(nx.edge_bfs(G)) assert edges == [] def test_graph_single_source(self): G = nx.Graph(self.edges) G.add_edge(4, 5) - x = list(edge_bfs(G, [0])) + x = list(nx.edge_bfs(G, [0])) x_ = [(0, 1), (0, 2), (1, 2), (1, 3)] assert x == x_ def test_graph(self): G = nx.Graph(self.edges) - x = list(edge_bfs(G, self.nodes)) + x = list(nx.edge_bfs(G, self.nodes)) x_ = [(0, 1), (0, 2), (1, 2), (1, 3)] assert x == x_ def test_digraph(self): G = nx.DiGraph(self.edges) - x = list(edge_bfs(G, self.nodes)) + x = list(nx.edge_bfs(G, self.nodes)) x_ = [(0, 1), (1, 0), (2, 0), (2, 1), (3, 1)] assert x == x_ def test_digraph_orientation_invalid(self): G = nx.DiGraph(self.edges) - edge_iterator = edge_bfs(G, self.nodes, orientation="hello") + edge_iterator = nx.edge_bfs(G, self.nodes, orientation="hello") pytest.raises(nx.NetworkXError, list, edge_iterator) def test_digraph_orientation_none(self): G = nx.DiGraph(self.edges) - x = list(edge_bfs(G, self.nodes, orientation=None)) + x = list(nx.edge_bfs(G, self.nodes, orientation=None)) x_ = [(0, 1), (1, 0), (2, 0), (2, 1), (3, 1)] assert x == x_ def test_digraph_orientation_original(self): G = nx.DiGraph(self.edges) - x = list(edge_bfs(G, self.nodes, orientation="original")) + x = list(nx.edge_bfs(G, self.nodes, orientation="original")) x_ = [ (0, 1, FORWARD), (1, 0, FORWARD), @@ -64,13 +60,13 @@ class TestEdgeBFS: def test_digraph2(self): G = nx.DiGraph() nx.add_path(G, range(4)) - x = list(edge_bfs(G, [0])) + x = list(nx.edge_bfs(G, [0])) x_ = [(0, 1), (1, 2), (2, 3)] assert x == x_ def test_digraph_rev(self): G = nx.DiGraph(self.edges) - x = list(edge_bfs(G, self.nodes, orientation="reverse")) + x = list(nx.edge_bfs(G, self.nodes, orientation="reverse")) x_ = [ (1, 0, REVERSE), (2, 0, REVERSE), @@ -83,13 +79,13 @@ class TestEdgeBFS: def test_digraph_rev2(self): G = nx.DiGraph() nx.add_path(G, range(4)) - x = list(edge_bfs(G, [3], orientation="reverse")) + x = list(nx.edge_bfs(G, [3], orientation="reverse")) x_ = [(2, 3, REVERSE), (1, 2, REVERSE), (0, 1, REVERSE)] assert x == x_ def test_multigraph(self): G = nx.MultiGraph(self.edges) - x = list(edge_bfs(G, self.nodes)) + x = list(nx.edge_bfs(G, self.nodes)) x_ = [(0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 2, 0), (1, 2, 0), (1, 3, 0)] # This is an example of where hash randomization can break. # There are 3! * 2 alternative outputs, such as: @@ -101,13 +97,13 @@ class TestEdgeBFS: def test_multidigraph(self): G = nx.MultiDiGraph(self.edges) - x = list(edge_bfs(G, self.nodes)) + x = list(nx.edge_bfs(G, self.nodes)) x_ = [(0, 1, 0), (1, 0, 0), (1, 0, 1), (2, 0, 0), (2, 1, 0), (3, 1, 0)] assert x == x_ def test_multidigraph_rev(self): G = nx.MultiDiGraph(self.edges) - x = list(edge_bfs(G, self.nodes, orientation="reverse")) + x = list(nx.edge_bfs(G, self.nodes, orientation="reverse")) x_ = [ (1, 0, 0, REVERSE), (1, 0, 1, REVERSE), @@ -120,7 +116,7 @@ class TestEdgeBFS: def test_digraph_ignore(self): G = nx.DiGraph(self.edges) - x = list(edge_bfs(G, self.nodes, orientation="ignore")) + x = list(nx.edge_bfs(G, self.nodes, orientation="ignore")) x_ = [ (0, 1, FORWARD), (1, 0, REVERSE), @@ -133,13 +129,13 @@ class TestEdgeBFS: def test_digraph_ignore2(self): G = nx.DiGraph() nx.add_path(G, range(4)) - x = list(edge_bfs(G, [0], orientation="ignore")) + x = list(nx.edge_bfs(G, [0], orientation="ignore")) x_ = [(0, 1, FORWARD), (1, 2, FORWARD), (2, 3, FORWARD)] assert x == x_ def test_multidigraph_ignore(self): G = nx.MultiDiGraph(self.edges) - x = list(edge_bfs(G, self.nodes, orientation="ignore")) + x = list(nx.edge_bfs(G, self.nodes, orientation="ignore")) x_ = [ (0, 1, 0, FORWARD), (1, 0, 0, REVERSE), diff --git a/networkx/algorithms/traversal/tests/test_edgedfs.py b/networkx/algorithms/traversal/tests/test_edgedfs.py index 6c12ae21..7c1967cc 100644 --- a/networkx/algorithms/traversal/tests/test_edgedfs.py +++ b/networkx/algorithms/traversal/tests/test_edgedfs.py @@ -1,11 +1,8 @@ import pytest import networkx as nx - -edge_dfs = nx.algorithms.edge_dfs - -FORWARD = nx.algorithms.edgedfs.FORWARD -REVERSE = nx.algorithms.edgedfs.REVERSE +from networkx.algorithms import edge_dfs +from networkx.algorithms.traversal.edgedfs import FORWARD, REVERSE # These tests can fail with hash randomization. The easiest and clearest way # to write these unit tests is for the edges to be output in an expected total diff --git a/networkx/classes/graphviews.py b/networkx/classes/graphviews.py index 4b276292..fb5dd63b 100644 --- a/networkx/classes/graphviews.py +++ b/networkx/classes/graphviews.py @@ -153,13 +153,13 @@ def subgraph_view(G, filter_node=no_filter, filter_edge=no_filter): if G.is_multigraph(): Adj = FilterMultiAdjacency - def reverse_edge(u, v, k): + def reverse_edge(u, v, k=None): return filter_edge(v, u, k) else: Adj = FilterAdjacency - def reverse_edge(u, v): + def reverse_edge(u, v, k=None): return filter_edge(v, u) if G.is_directed(): diff --git a/networkx/classes/tests/test_multigraph.py b/networkx/classes/tests/test_multigraph.py index f83378a6..ad9d6fd2 100644 --- a/networkx/classes/tests/test_multigraph.py +++ b/networkx/classes/tests/test_multigraph.py @@ -217,7 +217,7 @@ class TestMultiGraph(BaseMultiGraphTester, _TestGraph): dol = {"a": ["b"]} multiple_edge = [("a", "b", "traits", etraits), ("a", "b", "graphics", egraphics)] - single_edge = [("a", "b", 0, {})] + single_edge = [("a", "b", 0, {})] # type: ignore single_edge1 = [("a", "b", 0, edata)] single_edge2 = [("a", "b", 0, etraits)] single_edge3 = [("a", "b", 0, {"traits": etraits, "s": "foo"})] diff --git a/networkx/drawing/layout.py b/networkx/drawing/layout.py index c16446e2..73e52bee 100644 --- a/networkx/drawing/layout.py +++ b/networkx/drawing/layout.py @@ -556,8 +556,7 @@ def _fruchterman_reingold( pos += delta_pos # cool temperature t -= dt - err = np.linalg.norm(delta_pos) / nnodes - if err < threshold: + if (np.linalg.norm(delta_pos) / nnodes) < threshold: break return pos @@ -631,8 +630,7 @@ def _sparse_fruchterman_reingold( pos += delta_pos # cool temperature t -= dt - err = np.linalg.norm(delta_pos) / nnodes - if err < threshold: + if (np.linalg.norm(delta_pos) / nnodes) < threshold: break return pos diff --git a/networkx/generators/line.py b/networkx/generators/line.py index 55954c74..466691f6 100644 --- a/networkx/generators/line.py +++ b/networkx/generators/line.py @@ -114,12 +114,12 @@ def _node_func(G): """ if G.is_multigraph(): - def sorted_node(u, v, key): + def sorted_node(u, v, key=None): return (u, v, key) if u <= v else (v, u, key) else: - def sorted_node(u, v): + def sorted_node(u, v, key=None): return (u, v) if u <= v else (v, u) return sorted_node diff --git a/networkx/readwrite/graphml.py b/networkx/readwrite/graphml.py index a1ed7ad1..2e98373c 100644 --- a/networkx/readwrite/graphml.py +++ b/networkx/readwrite/graphml.py @@ -999,14 +999,14 @@ class GraphMLReader(GraphML): data["label"] = node_label.text # check all the different types of edges avaivable in yEd. - for e in [ + for edge_type in [ "PolyLineEdge", "SplineEdge", "QuadCurveEdge", "BezierEdge", "ArcEdge", ]: - pref = f"{{{self.NS_Y}}}{e}/{{{self.NS_Y}}}" + pref = f"{{{self.NS_Y}}}{edge_type}/{{{self.NS_Y}}}" edge_label = data_element.find(f"{pref}EdgeLabel") if edge_label is not None: break diff --git a/networkx/readwrite/nx_shp.py b/networkx/readwrite/nx_shp.py index 4dd01be5..74bc0595 100644 --- a/networkx/readwrite/nx_shp.py +++ b/networkx/readwrite/nx_shp.py @@ -327,10 +327,10 @@ def write_shp(G, outdir): # New edge attribute write support merged into edge loop edge_fields = {} # storage for field names and their data types - for e in G.edges(data=True): - data = G.get_edge_data(*e) - g = netgeometry(e, data) - attributes, edges = create_attributes(e[2], edge_fields, edges) + for edge in G.edges(data=True): + data = G.get_edge_data(*edge) + g = netgeometry(edge, data) + attributes, edges = create_attributes(edge[2], edge_fields, edges) create_feature(g, edges, attributes) nodes, edges = None, None diff --git a/networkx/readwrite/tests/test_gml.py b/networkx/readwrite/tests/test_gml.py index 51c08c4f..50facec5 100644 --- a/networkx/readwrite/tests/test_gml.py +++ b/networkx/readwrite/tests/test_gml.py @@ -288,7 +288,7 @@ graph ]""" assert data == answer - def test_float_label(self): + def test_special_float_label(self): special_floats = [float("nan"), float("+inf"), float("-inf")] try: import numpy as np diff --git a/networkx/utils/decorators.py b/networkx/utils/decorators.py index 14bac852..e8e4bff5 100644 --- a/networkx/utils/decorators.py +++ b/networkx/utils/decorators.py @@ -92,10 +92,12 @@ def not_implemented_for(*graph_types): # To handle new extensions, define a function accepting a `path` and `mode`. # Then add the extension to _dispatch_dict. -_dispatch_dict = defaultdict(lambda: open) -_dispatch_dict[".gz"] = gzip.open -_dispatch_dict[".bz2"] = bz2.BZ2File -_dispatch_dict[".gzip"] = gzip.open +fopeners = { + ".gz": gzip.open, + ".gzip": gzip.open, + ".bz2": bz2.BZ2File, +} +_dispatch_dict = defaultdict(lambda: open, **fopeners) # type: ignore def open_file(path_arg, mode="r"): diff --git a/requirements/developer.txt b/requirements/developer.txt index 0fea0d07..cacc7020 100644 --- a/requirements/developer.txt +++ b/requirements/developer.txt @@ -1,3 +1,4 @@ black==21.9b0 pyupgrade>=2.29.0 pre-commit>=2.15 +mypy>=0.910 |