From 818ef98d374f1fddb5b2cfe545dea3b1102fffa8 Mon Sep 17 00:00:00 2001 From: ANSHUL SINGH <72524975+ekanshul@users.noreply.github.com> Date: Sat, 12 Sep 2026 01:24:56 +0530 Subject: [PATCH 1/3] [networkx] Accept any node/edge data types in graph parameters outside `algorithms` Graph parameters annotated as `Graph[_Node]` only accept the default `dict[str, Any]` node and edge data, so graphs with other `Mapping` data types are rejected by functions that never look at the data. Type them as `Graph[_Node, _NodeData, _EdgeData]` in `classes.function`, `convert`, `convert_matrix`, `generators`, `linalg`, `readwrite` and `utils`, as already done for `classes` and `drawing`. Return types of graph-building functions are unchanged; `edge_subgraph()` and `restricted_view()` now return the input graph's type. Part of #16365. Co-Authored-By: Claude Fable 5.1 --- .../test_cases/check_graph_data_types.py | 44 +++++++++ stubs/networkx/networkx/classes/function.pyi | 90 ++++++++++--------- stubs/networkx/networkx/convert.pyi | 8 +- stubs/networkx/networkx/convert_matrix.pyi | 15 ++-- stubs/networkx/networkx/generators/ego.pyi | 6 +- .../networkx/generators/expanders.pyi | 4 +- .../networkx/generators/geometric.pyi | 4 +- stubs/networkx/networkx/generators/line.pyi | 8 +- .../networkx/generators/mycielski.pyi | 4 +- .../generators/spectral_graph_forge.pyi | 6 +- .../networkx/generators/stochastic.pyi | 4 +- .../networkx/linalg/algebraicconnectivity.pyi | 10 +-- stubs/networkx/networkx/linalg/attrmatrix.pyi | 6 +- .../networkx/linalg/bethehessianmatrix.pyi | 6 +- .../networkx/networkx/linalg/graphmatrix.pyi | 9 +- .../networkx/linalg/laplacianmatrix.pyi | 12 +-- .../networkx/linalg/modularitymatrix.pyi | 6 +- stubs/networkx/networkx/linalg/spectrum.pyi | 14 +-- stubs/networkx/networkx/readwrite/adjlist.pyi | 10 ++- .../networkx/networkx/readwrite/edgelist.pyi | 14 ++- stubs/networkx/networkx/readwrite/gexf.pyi | 18 ++-- stubs/networkx/networkx/readwrite/gml.pyi | 10 ++- stubs/networkx/networkx/readwrite/graph6.pyi | 13 ++- stubs/networkx/networkx/readwrite/graphml.pyi | 20 ++--- .../readwrite/json_graph/adjacency.pyi | 6 +- .../readwrite/json_graph/cytoscape.pyi | 4 +- .../readwrite/json_graph/node_link.pyi | 4 +- .../networkx/readwrite/json_graph/tree.pyi | 6 +- .../networkx/readwrite/multiline_adjlist.pyi | 10 ++- stubs/networkx/networkx/readwrite/p2g.pyi | 4 +- stubs/networkx/networkx/readwrite/pajek.pyi | 6 +- stubs/networkx/networkx/readwrite/sparse6.pyi | 9 +- stubs/networkx/networkx/utils/misc.pyi | 4 +- stubs/networkx/networkx/utils/rcm.pyi | 10 +-- 34 files changed, 247 insertions(+), 157 deletions(-) create mode 100644 stubs/networkx/@tests/test_cases/check_graph_data_types.py diff --git a/stubs/networkx/@tests/test_cases/check_graph_data_types.py b/stubs/networkx/@tests/test_cases/check_graph_data_types.py new file mode 100644 index 000000000000..84807112f224 --- /dev/null +++ b/stubs/networkx/@tests/test_cases/check_graph_data_types.py @@ -0,0 +1,44 @@ +from __future__ import annotations + +from collections.abc import Iterator, Mapping +from typing import Any + +from typing_extensions import assert_type + +import networkx as nx +from networkx.utils.rcm import reverse_cuthill_mckee_ordering + + +class NodeData(Mapping[str, Any]): + def __getitem__(self, key: str) -> Any: ... + def __iter__(self) -> Iterator[str]: ... + def __len__(self) -> int: ... + + +# Functions that only read a graph accept any node/edge data types that satisfy +# the `Mapping[str, Any]` bound, not just the `dict[str, Any]` default. +G = nx.Graph[int, NodeData, dict[str, Any]]() +assert_type(nx.degree_histogram(G), list[int]) +assert_type(nx.to_dict_of_lists(G), dict[int, list[int]]) +assert_type(nx.is_weighted(G), bool) +nx.number_of_nodes(G) +nx.write_gml(G, "graph.gml") +nx.generate_adjlist(G) +nx.node_link_data(G) +nx.adjacency_matrix(G) +nx.laplacian_spectrum(G) +reverse_cuthill_mckee_ordering(G) + +D = nx.DiGraph[str, NodeData, NodeData]() +nx.number_of_edges(D) +nx.write_edgelist(D, "graph.edgelist") +nx.directed_laplacian_matrix(D) + +# Views keep the data types of the graph they come from. +assert_type(nx.edge_subgraph(G, [(1, 2)]), nx.Graph[int, NodeData, dict[str, Any]]) +assert_type(nx.restricted_view(G, [1], [(1, 2)]), nx.Graph[int, NodeData, dict[str, Any]]) + +# The default data types work as before. +H = nx.Graph[str]() +assert_type(nx.to_dict_of_lists(H), dict[str, list[str]]) +nx.write_gml(H, "graph.gml") diff --git a/stubs/networkx/networkx/classes/function.pyi b/stubs/networkx/networkx/classes/function.pyi index 17d152c96157..dc625ef28fc6 100644 --- a/stubs/networkx/networkx/classes/function.pyi +++ b/stubs/networkx/networkx/classes/function.pyi @@ -1,6 +1,6 @@ from _typeshed import Incomplete, SupportsItems, SupportsKeysAndGetItem, Unused from collections.abc import Callable, Collection, Generator, Hashable, Iterable, Iterator -from typing import Literal, TypeVar, overload +from typing import Any, Literal, TypeVar, overload from networkx import _dispatchable from networkx.algorithms.planarity import PlanarEmbedding @@ -53,34 +53,34 @@ __all__ = [ _U = TypeVar("_U") -def nodes(G: Graph[_Node]): ... -def edges(G: Graph[_Node], nbunch=None): ... -def degree(G: Graph[_Node], nbunch=None, weight=None): ... -def neighbors(G: Graph[_Node], n): ... -def number_of_nodes(G: Graph[_Node]): ... -def number_of_edges(G: Graph[_Node]): ... -def density(G: Graph[_Node]): ... -def degree_histogram(G: Graph[_Node]) -> list[int]: ... - +def nodes(G: Graph[_Node, _NodeData, _EdgeData]): ... +def edges(G: Graph[_Node, _NodeData, _EdgeData], nbunch=None): ... +def degree(G: Graph[_Node, _NodeData, _EdgeData], nbunch=None, weight=None): ... +def neighbors(G: Graph[_Node, _NodeData, _EdgeData], n): ... +def number_of_nodes(G: Graph[_Node, _NodeData, _EdgeData]): ... +def number_of_edges(G: Graph[_Node, _NodeData, _EdgeData]): ... +def density(G: Graph[_Node, _NodeData, _EdgeData]): ... +def degree_histogram(G: Graph[_Node, _NodeData, _EdgeData]) -> list[int]: ... @overload def is_directed(G: PlanarEmbedding[Hashable]) -> Literal[False]: ... # type: ignore[misc] # Incompatible return types @overload def is_directed(G: DiGraph[Hashable]) -> Literal[True]: ... # type: ignore[misc] # Incompatible return types @overload def is_directed(G: Graph[Hashable]) -> Literal[False]: ... - -def freeze(G: Graph[_Node]): ... +def freeze(G: Graph[_Node, _NodeData, _EdgeData]): ... def is_frozen(G: Graph[Incomplete]) -> bool: ... def add_star(G_to_add_to: Graph[Incomplete], nodes_for_star: Iterable[Incomplete], **attr) -> None: ... def add_path(G_to_add_to: Graph[Incomplete], nodes_for_path: Iterable[Incomplete], **attr) -> None: ... def add_cycle(G_to_add_to: Graph[Incomplete], nodes_for_cycle: Iterable[Incomplete], **attr) -> None: ... -def subgraph(G: Graph[_Node], nbunch: Iterable[Incomplete]): ... +def subgraph(G: Graph[_Node, _NodeData, _EdgeData], nbunch: Iterable[Incomplete]): ... def induced_subgraph(G: Graph[_Node, _NodeData, _EdgeData], nbunch: _NBunch[_Node]) -> Graph[_Node, _NodeData, _EdgeData]: ... -def edge_subgraph(G: Graph[_Node], edges: Iterable[Incomplete]) -> Graph[Incomplete]: ... -def restricted_view(G: Graph[_Node], nodes: Iterable[Incomplete], edges: Iterable[Incomplete]) -> Graph[Incomplete]: ... +def edge_subgraph(G: Graph[_Node, _NodeData, _EdgeData], edges: Iterable[Incomplete]) -> Graph[_Node, _NodeData, _EdgeData]: ... +def restricted_view( + G: Graph[_Node, _NodeData, _EdgeData], nodes: Iterable[Incomplete], edges: Iterable[Incomplete] +) -> Graph[_Node, _NodeData, _EdgeData]: ... def to_directed(graph): ... def to_undirected(graph): ... -def create_empty_copy(G: Graph[_Node], with_data: bool = True): ... +def create_empty_copy(G: Graph[_Node, _NodeData, _EdgeData], with_data: bool = True): ... # incomplete: Can "Any scalar value" be enforced? @overload @@ -94,22 +94,20 @@ def set_node_attributes( ) -> None: ... @overload def set_node_attributes( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], values: SupportsItems[_Node, SupportsKeysAndGetItem[Incomplete, Incomplete] | Iterable[tuple[Incomplete, Incomplete]]], name: None = None, *, backend=None, **backend_kwargs, ) -> None: ... - @_dispatchable -def get_node_attributes(G: Graph[_Node], name: str, default=None) -> dict[_Node, Incomplete]: ... +def get_node_attributes(G: Graph[_Node, _NodeData, _EdgeData], name: str, default=None) -> dict[_Node, Incomplete]: ... @_dispatchable -def remove_node_attributes(G: Graph[_Node], *attr_names, nbunch=None) -> None: ... - +def remove_node_attributes(G: Graph[_Node, _NodeData, _EdgeData], *attr_names, nbunch=None) -> None: ... @overload def set_edge_attributes( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], values: SupportsItems[tuple[_Node, _Node], Incomplete], name: str, *, @@ -118,7 +116,7 @@ def set_edge_attributes( ) -> None: ... @overload def set_edge_attributes( - G: MultiGraph[_Node], + G: MultiGraph[_Node, _NodeData, _EdgeData], values: dict[tuple[_Node, _Node, Incomplete], Incomplete], name: str, *, @@ -129,26 +127,30 @@ def set_edge_attributes( def set_edge_attributes( G: Graph[Hashable], values, name: None = None, *, backend: str | None = None, **backend_kwargs ) -> None: ... - @_dispatchable -def get_edge_attributes(G: Graph[_Node], name: str, default=None) -> dict[tuple[_Node, _Node], Incomplete]: ... +def get_edge_attributes( + G: Graph[_Node, _NodeData, _EdgeData], name: str, default=None +) -> dict[tuple[_Node, _Node], Incomplete]: ... @_dispatchable -def remove_edge_attributes(G: Graph[_Node], *attr_names, ebunch=None) -> None: ... -def all_neighbors(graph: Graph[_Node], node: _Node) -> Iterator[_Node]: ... -def non_neighbors(graph: Graph[_Node], node: _Node) -> Generator[_Node]: ... -def non_edges(graph: Graph[_Node]) -> Generator[tuple[_Node, _Node]]: ... -def common_neighbors(G: Graph[_Node], u: _Node, v: _Node) -> Generator[_Node]: ... +def remove_edge_attributes(G: Graph[_Node, _NodeData, _EdgeData], *attr_names, ebunch=None) -> None: ... +def all_neighbors(graph: Graph[_Node, _NodeData, _EdgeData], node: _Node) -> Iterator[_Node]: ... +def non_neighbors(graph: Graph[_Node, _NodeData, _EdgeData], node: _Node) -> Generator[_Node]: ... +def non_edges(graph: Graph[_Node, _NodeData, _EdgeData]) -> Generator[tuple[_Node, _Node]]: ... +def common_neighbors(G: Graph[_Node, _NodeData, _EdgeData], u: _Node, v: _Node) -> Generator[_Node]: ... @_dispatchable -def is_weighted(G: Graph[_Node], edge: tuple[_Node, _Node] | None = None, weight: str = "weight") -> bool: ... +def is_weighted( + G: Graph[_Node, _NodeData, _EdgeData], edge: tuple[_Node, _Node] | None = None, weight: str = "weight" +) -> bool: ... @_dispatchable -def is_negatively_weighted(G: Graph[_Node], edge: tuple[_Node, _Node] | None = None, weight: str = "weight") -> bool: ... +def is_negatively_weighted( + G: Graph[_Node, _NodeData, _EdgeData], edge: tuple[_Node, _Node] | None = None, weight: str = "weight" +) -> bool: ... @_dispatchable def is_empty(G: Graph[Hashable]) -> bool: ... -def nodes_with_selfloops(G: Graph[_Node]) -> Generator[_Node]: ... - +def nodes_with_selfloops(G: Graph[_Node, _NodeData, _EdgeData]) -> Generator[_Node]: ... @overload def selfloop_edges( - G: Graph[_Node], data: Literal[False] = False, keys: Literal[False] = False, default=None + G: Graph[_Node, _NodeData, _EdgeData], data: Literal[False] = False, keys: Literal[False] = False, default=None ) -> Generator[tuple[_Node, _Node]]: ... @overload def selfloop_edges( @@ -156,15 +158,15 @@ def selfloop_edges( ) -> Generator[tuple[_Node, _Node, _EdgeData]]: ... @overload def selfloop_edges( - G: Graph[_Node], data: str, keys: Literal[False] = False, default: _U | None = None + G: Graph[_Node, Any, Any], data: str, keys: Literal[False] = False, default: _U | None = None ) -> Generator[tuple[_Node, _Node, _U]]: ... @overload def selfloop_edges( - G: Graph[_Node], data: Literal[False], keys: Literal[True], default=None + G: Graph[_Node, _NodeData, _EdgeData], data: Literal[False], keys: Literal[True], default=None ) -> Generator[tuple[_Node, _Node, int]]: ... @overload def selfloop_edges( - G: Graph[_Node], data: Literal[False] = False, *, keys: Literal[True], default=None + G: Graph[_Node, _NodeData, _EdgeData], data: Literal[False] = False, *, keys: Literal[True], default=None ) -> Generator[tuple[_Node, _Node, int]]: ... @overload def selfloop_edges( @@ -172,11 +174,13 @@ def selfloop_edges( ) -> Generator[tuple[_Node, _Node, int, _EdgeData]]: ... @overload def selfloop_edges( - G: Graph[_Node], data: str, keys: Literal[True], default: _U | None = None + G: Graph[_Node, Any, Any], data: str, keys: Literal[True], default: _U | None = None ) -> Generator[tuple[_Node, _Node, int, _U]]: ... - @_dispatchable def number_of_selfloops(G: Graph[Hashable]) -> int: ... -def is_path(G: Graph[_Node], path: Iterable[Incomplete]) -> bool: ... -def path_weight(G: Graph[_Node], path: Collection[Incomplete], weight: str) -> int: ... -def describe(G: Graph[_Node], describe_hook: Callable[[Graph[_Node]], dict[str, Incomplete]] | None = None) -> None: ... +def is_path(G: Graph[_Node, _NodeData, _EdgeData], path: Iterable[Incomplete]) -> bool: ... +def path_weight(G: Graph[_Node, _NodeData, _EdgeData], path: Collection[Incomplete], weight: str) -> int: ... +def describe( + G: Graph[_Node, _NodeData, _EdgeData], + describe_hook: Callable[[Graph[_Node, _NodeData, _EdgeData]], dict[str, Incomplete]] | None = None, +) -> None: ... diff --git a/stubs/networkx/networkx/convert.pyi b/stubs/networkx/networkx/convert.pyi index b6bd41f09185..a994394f1438 100644 --- a/stubs/networkx/networkx/convert.pyi +++ b/stubs/networkx/networkx/convert.pyi @@ -20,13 +20,15 @@ def to_networkx_graph( multigraph_input: bool = False, ) -> Graph[_Node, _NodeData, _EdgeData]: ... @_dispatchable -def to_dict_of_lists(G: Graph[_Node], nodelist: Collection[_Node] | None = None) -> dict[_Node, list[_Node]]: ... +def to_dict_of_lists( + G: Graph[_Node, _NodeData, _EdgeData], nodelist: Collection[_Node] | None = None +) -> dict[_Node, list[_Node]]: ... @_dispatchable def from_dict_of_lists( d: dict[_Node, Iterable[_Node]], create_using: Graph[Incomplete] | type[Graph[Incomplete]] | None = None ) -> Graph[_Node]: ... def to_dict_of_dicts( - G: Graph[_Node], nodelist: Collection[_Node] | None = None, edge_data: float | None = None + G: Graph[_Node, _NodeData, _EdgeData], nodelist: Collection[_Node] | None = None, edge_data: float | None = None ) -> dict[Incomplete, Incomplete]: ... @_dispatchable def from_dict_of_dicts( @@ -35,7 +37,7 @@ def from_dict_of_dicts( multigraph_input: bool = False, ) -> Graph[Incomplete]: ... @_dispatchable -def to_edgelist(G: Graph[_Node], nodelist: Collection[_Node] | None = None): ... +def to_edgelist(G: Graph[_Node, _NodeData, _EdgeData], nodelist: Collection[_Node] | None = None): ... @_dispatchable def from_edgelist( edgelist: Iterable[Incomplete], create_using: Graph[Incomplete] | type[Graph[Incomplete]] | None = None diff --git a/stubs/networkx/networkx/convert_matrix.pyi b/stubs/networkx/networkx/convert_matrix.pyi index 98179313bcea..bde3ba304f64 100644 --- a/stubs/networkx/networkx/convert_matrix.pyi +++ b/stubs/networkx/networkx/convert_matrix.pyi @@ -4,7 +4,7 @@ from typing import Literal, TypeAlias, TypeVar, overload import numpy import numpy as np -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable # stub_uploader won't allow pandas-stubs in the requires field https://github.com/typeshed-internal/stub_uploader/issues/90 @@ -30,7 +30,7 @@ __all__ = [ @_dispatchable def to_pandas_adjacency( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], nodelist: _Axes[_Node] | None = None, dtype: numpy.dtype[Incomplete] | None = None, order: numpy._OrderCF = None, @@ -38,22 +38,19 @@ def to_pandas_adjacency( weight: str = "weight", nonedge: float = 0.0, ) -> _DataFrame: ... - @overload def from_pandas_adjacency(df: _DataFrame, create_using: type[_G]) -> _G: ... @overload def from_pandas_adjacency(df: _DataFrame, create_using: None = None) -> Graph[Incomplete]: ... - @_dispatchable def to_pandas_edgelist( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], source: str | int = "source", target: str | int = "target", nodelist: Iterable[_Node] | None = None, dtype: _ExtensionDtype | None = None, edge_key: str | int | None = None, ) -> _DataFrame: ... - @overload def from_pandas_edgelist( df: _DataFrame, @@ -82,10 +79,9 @@ def from_pandas_edgelist( create_using: None = None, edge_key: str | None = None, ) -> Graph[Incomplete]: ... - @_dispatchable def to_scipy_sparse_array( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], nodelist: Collection[_Node] | None = None, dtype: np.dtype[Incomplete] | None = None, weight: str | None = "weight", @@ -100,7 +96,7 @@ def from_scipy_sparse_array( ): ... @_dispatchable def to_numpy_array( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], nodelist: Collection[_Node] | None = None, dtype: numpy.dtype[Incomplete] | None = None, order: numpy._OrderCF = None, @@ -108,7 +104,6 @@ def to_numpy_array( weight: str = "weight", nonedge: float = 0.0, ) -> numpy.ndarray[Incomplete, numpy.dtype[Incomplete]]: ... - @overload def from_numpy_array( A: numpy.ndarray[Incomplete, Incomplete], parallel_edges: bool = False, create_using: None = None diff --git a/stubs/networkx/networkx/generators/ego.pyi b/stubs/networkx/networkx/generators/ego.pyi index 17a15862aa1a..a7ccc4f2a869 100644 --- a/stubs/networkx/networkx/generators/ego.pyi +++ b/stubs/networkx/networkx/generators/ego.pyi @@ -1,7 +1,9 @@ -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = ["ego_graph"] @_dispatchable -def ego_graph(G: Graph[_Node], n, radius: float = 1, center: bool = True, undirected: bool = False, distance=None): ... +def ego_graph( + G: Graph[_Node, _NodeData, _EdgeData], n, radius: float = 1, center: bool = True, undirected: bool = False, distance=None +): ... diff --git a/stubs/networkx/networkx/generators/expanders.pyi b/stubs/networkx/networkx/generators/expanders.pyi index 72d061145a1a..7ad695b70530 100644 --- a/stubs/networkx/networkx/generators/expanders.pyi +++ b/stubs/networkx/networkx/generators/expanders.pyi @@ -1,7 +1,7 @@ from _typeshed import Incomplete from typing_extensions import deprecated -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.classes.multigraph import MultiGraph from networkx.utils.backends import _dispatchable @@ -31,6 +31,6 @@ def maybe_regular_expander_graph(n: int, d: int, *, create_using=None, max_tries ) def maybe_regular_expander(n, d, *, create_using=None, max_tries: int = 100, seed=None): ... @_dispatchable -def is_regular_expander(G: Graph[_Node], *, epsilon: float = 0) -> bool: ... +def is_regular_expander(G: Graph[_Node, _NodeData, _EdgeData], *, epsilon: float = 0) -> bool: ... @_dispatchable def random_regular_expander_graph(n: int, d: int, *, epsilon=0, create_using=None, max_tries=100, seed=None): ... diff --git a/stubs/networkx/networkx/generators/geometric.pyi b/stubs/networkx/networkx/generators/geometric.pyi index 1d12fb9c17be..ee215cd30d31 100644 --- a/stubs/networkx/networkx/generators/geometric.pyi +++ b/stubs/networkx/networkx/generators/geometric.pyi @@ -1,7 +1,7 @@ from _typeshed import Incomplete from collections.abc import Callable, Iterable -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = [ @@ -16,7 +16,7 @@ __all__ = [ ] @_dispatchable -def geometric_edges(G: Graph[_Node], radius: float, p: float = 2) -> list[Incomplete]: ... +def geometric_edges(G: Graph[_Node, _NodeData, _EdgeData], radius: float, p: float = 2) -> list[Incomplete]: ... @_dispatchable def random_geometric_graph( n: int | Iterable[Incomplete], diff --git a/stubs/networkx/networkx/generators/line.pyi b/stubs/networkx/networkx/generators/line.pyi index a9cd56c23186..f87f7453a1d0 100644 --- a/stubs/networkx/networkx/generators/line.pyi +++ b/stubs/networkx/networkx/generators/line.pyi @@ -1,11 +1,13 @@ from _typeshed import Incomplete -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = ["line_graph", "inverse_line_graph"] @_dispatchable -def line_graph(G: Graph[_Node], create_using: Graph[Incomplete] | type[Graph[Incomplete]] | None = None) -> Graph[Incomplete]: ... +def line_graph( + G: Graph[_Node, _NodeData, _EdgeData], create_using: Graph[Incomplete] | type[Graph[Incomplete]] | None = None +) -> Graph[Incomplete]: ... @_dispatchable -def inverse_line_graph(G: Graph[_Node]) -> Graph[Incomplete]: ... +def inverse_line_graph(G: Graph[_Node, _NodeData, _EdgeData]) -> Graph[Incomplete]: ... diff --git a/stubs/networkx/networkx/generators/mycielski.pyi b/stubs/networkx/networkx/generators/mycielski.pyi index ba383edc6ed0..ecdd27563be0 100644 --- a/stubs/networkx/networkx/generators/mycielski.pyi +++ b/stubs/networkx/networkx/generators/mycielski.pyi @@ -1,11 +1,11 @@ from _typeshed import Incomplete -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = ["mycielskian", "mycielski_graph"] @_dispatchable -def mycielskian(G: Graph[_Node], iterations: int = 1) -> Graph[Incomplete]: ... +def mycielskian(G: Graph[_Node, _NodeData, _EdgeData], iterations: int = 1) -> Graph[Incomplete]: ... @_dispatchable def mycielski_graph(n: int) -> Graph[Incomplete]: ... diff --git a/stubs/networkx/networkx/generators/spectral_graph_forge.pyi b/stubs/networkx/networkx/generators/spectral_graph_forge.pyi index 2822fc3544a7..ee68fa302a42 100644 --- a/stubs/networkx/networkx/generators/spectral_graph_forge.pyi +++ b/stubs/networkx/networkx/generators/spectral_graph_forge.pyi @@ -1,9 +1,11 @@ from _typeshed import Incomplete -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = ["spectral_graph_forge"] @_dispatchable -def spectral_graph_forge(G: Graph[_Node], alpha: float, transformation: str = "identity", seed=None) -> Graph[Incomplete]: ... +def spectral_graph_forge( + G: Graph[_Node, _NodeData, _EdgeData], alpha: float, transformation: str = "identity", seed=None +) -> Graph[Incomplete]: ... diff --git a/stubs/networkx/networkx/generators/stochastic.pyi b/stubs/networkx/networkx/generators/stochastic.pyi index c52c2a9b19e1..795b9578d273 100644 --- a/stubs/networkx/networkx/generators/stochastic.pyi +++ b/stubs/networkx/networkx/generators/stochastic.pyi @@ -1,8 +1,8 @@ from networkx.classes.digraph import DiGraph -from networkx.classes.graph import _Node +from networkx.classes.graph import _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = ["stochastic_graph"] @_dispatchable -def stochastic_graph(G: DiGraph[_Node], copy: bool = True, weight: str = "weight"): ... +def stochastic_graph(G: DiGraph[_Node, _NodeData, _EdgeData], copy: bool = True, weight: str = "weight"): ... diff --git a/stubs/networkx/networkx/linalg/algebraicconnectivity.pyi b/stubs/networkx/networkx/linalg/algebraicconnectivity.pyi index 3ff0fd053a4d..9d21aeb58156 100644 --- a/stubs/networkx/networkx/linalg/algebraicconnectivity.pyi +++ b/stubs/networkx/networkx/linalg/algebraicconnectivity.pyi @@ -2,14 +2,14 @@ from typing import Literal import numpy as np from networkx._typing import Array1D, Seed -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = ["algebraic_connectivity", "fiedler_vector", "spectral_ordering", "spectral_bisection"] @_dispatchable def algebraic_connectivity( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], weight: str | None = "weight", normalized: bool = False, tol: float = 1e-08, @@ -18,7 +18,7 @@ def algebraic_connectivity( ) -> float: ... @_dispatchable def fiedler_vector( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], weight: str | None = "weight", normalized: bool = False, tol: float = 1e-08, @@ -27,7 +27,7 @@ def fiedler_vector( ) -> Array1D[np.float64]: ... @_dispatchable def spectral_ordering( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], weight: str | None = "weight", normalized: bool = False, tol: float = 1e-08, @@ -36,7 +36,7 @@ def spectral_ordering( ) -> list[_Node]: ... @_dispatchable def spectral_bisection( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], weight: str | None = "weight", normalized: bool = False, tol: float = 1e-08, diff --git a/stubs/networkx/networkx/linalg/attrmatrix.pyi b/stubs/networkx/networkx/linalg/attrmatrix.pyi index 90b19c231e4d..f25c54fa33c0 100644 --- a/stubs/networkx/networkx/linalg/attrmatrix.pyi +++ b/stubs/networkx/networkx/linalg/attrmatrix.pyi @@ -3,7 +3,7 @@ from collections.abc import Collection from typing import Any, Literal from networkx._typing import Array2D -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable from numpy.typing import DTypeLike from scipy.sparse import lil_array # type: ignore[import-untyped] # pyright: ignore[reportMissingImports] @@ -12,7 +12,7 @@ __all__ = ["attr_matrix", "attr_sparse_matrix"] @_dispatchable def attr_matrix( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], edge_attr: str | None = None, node_attr: str | None = None, # runtime also accepts `Callable[[_Node], object]`, but it is not documented normalized: bool = False, # runtime also accepts `Callable[[_Node, _Node], object]`, but it is not documented @@ -27,7 +27,7 @@ def attr_matrix( ) -> Array2D[Incomplete] | tuple[Array2D[Incomplete], list[_Node] | list[Any]]: ... @_dispatchable def attr_sparse_matrix( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], edge_attr: str | None = None, node_attr: str | None = None, # runtime also accepts `Callable[[_Node], object]`, but it is not documented normalized: bool = False, # runtime also accepts `Callable[[_Node, _Node], object]`, but it is not documented diff --git a/stubs/networkx/networkx/linalg/bethehessianmatrix.pyi b/stubs/networkx/networkx/linalg/bethehessianmatrix.pyi index 6cc9100b9870..7c01eb3cbaa4 100644 --- a/stubs/networkx/networkx/linalg/bethehessianmatrix.pyi +++ b/stubs/networkx/networkx/linalg/bethehessianmatrix.pyi @@ -1,10 +1,12 @@ from collections.abc import Collection -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable from scipy.sparse import csr_array # type: ignore[import-untyped] # pyright: ignore[reportMissingImports] __all__ = ["bethe_hessian_matrix"] @_dispatchable -def bethe_hessian_matrix(G: Graph[_Node], r: float | None = None, nodelist: Collection[_Node] | None = None) -> csr_array: ... +def bethe_hessian_matrix( + G: Graph[_Node, _NodeData, _EdgeData], r: float | None = None, nodelist: Collection[_Node] | None = None +) -> csr_array: ... diff --git a/stubs/networkx/networkx/linalg/graphmatrix.pyi b/stubs/networkx/networkx/linalg/graphmatrix.pyi index 7d08761770d7..3a4b8c3ea974 100644 --- a/stubs/networkx/networkx/linalg/graphmatrix.pyi +++ b/stubs/networkx/networkx/linalg/graphmatrix.pyi @@ -1,6 +1,6 @@ from collections.abc import Collection, Hashable -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable from numpy.typing import DTypeLike from scipy.sparse import csc_array, csr_array # type: ignore[import-untyped] # pyright: ignore[reportMissingImports] @@ -9,7 +9,7 @@ __all__ = ["incidence_matrix", "adjacency_matrix"] @_dispatchable def incidence_matrix( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], nodelist: Collection[_Node] | None = None, edgelist: ( Collection[ @@ -27,5 +27,8 @@ def incidence_matrix( ) -> csc_array: ... @_dispatchable def adjacency_matrix( - G: Graph[_Node], nodelist: Collection[_Node] | None = None, dtype: DTypeLike | None = None, weight: str | None = "weight" + G: Graph[_Node, _NodeData, _EdgeData], + nodelist: Collection[_Node] | None = None, + dtype: DTypeLike | None = None, + weight: str | None = "weight", ) -> csr_array: ... diff --git a/stubs/networkx/networkx/linalg/laplacianmatrix.pyi b/stubs/networkx/networkx/linalg/laplacianmatrix.pyi index 089d31900cfb..d77108556486 100644 --- a/stubs/networkx/networkx/linalg/laplacianmatrix.pyi +++ b/stubs/networkx/networkx/linalg/laplacianmatrix.pyi @@ -4,7 +4,7 @@ from typing import Literal import numpy as np from networkx._typing import Array2D from networkx.classes.digraph import DiGraph -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable from scipy.sparse import csr_array # type: ignore[import-untyped] # pyright: ignore[reportMissingImports] @@ -16,14 +16,16 @@ __all__ = [ ] @_dispatchable -def laplacian_matrix(G: Graph[_Node], nodelist: Collection[_Node] | None = None, weight: str | None = "weight") -> csr_array: ... +def laplacian_matrix( + G: Graph[_Node, _NodeData, _EdgeData], nodelist: Collection[_Node] | None = None, weight: str | None = "weight" +) -> csr_array: ... @_dispatchable def normalized_laplacian_matrix( - G: Graph[_Node], nodelist: Collection[_Node] | None = None, weight: str | None = "weight" + G: Graph[_Node, _NodeData, _EdgeData], nodelist: Collection[_Node] | None = None, weight: str | None = "weight" ) -> csr_array: ... @_dispatchable def directed_laplacian_matrix( - G: DiGraph[_Node], + G: DiGraph[_Node, _NodeData, _EdgeData], nodelist: Collection[_Node] | None = None, weight: str | None = "weight", walk_type: Literal["random", "lazy", "pagerank"] | None = None, @@ -31,7 +33,7 @@ def directed_laplacian_matrix( ) -> Array2D[np.float64]: ... @_dispatchable def directed_combinatorial_laplacian_matrix( - G: DiGraph[_Node], + G: DiGraph[_Node, _NodeData, _EdgeData], nodelist: Collection[_Node] | None = None, weight: str | None = "weight", walk_type: Literal["random", "lazy", "pagerank"] | None = None, diff --git a/stubs/networkx/networkx/linalg/modularitymatrix.pyi b/stubs/networkx/networkx/linalg/modularitymatrix.pyi index d7537db42afc..1981d9929194 100644 --- a/stubs/networkx/networkx/linalg/modularitymatrix.pyi +++ b/stubs/networkx/networkx/linalg/modularitymatrix.pyi @@ -3,16 +3,16 @@ from collections.abc import Collection import numpy as np from networkx._typing import Array2D from networkx.classes.digraph import DiGraph -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = ["modularity_matrix", "directed_modularity_matrix"] @_dispatchable def modularity_matrix( - G: Graph[_Node], nodelist: Collection[_Node] | None = None, weight: str | None = None + G: Graph[_Node, _NodeData, _EdgeData], nodelist: Collection[_Node] | None = None, weight: str | None = None ) -> Array2D[np.float64]: ... @_dispatchable def directed_modularity_matrix( - G: DiGraph[_Node], nodelist: Collection[_Node] | None = None, weight: str | None = None + G: DiGraph[_Node, _NodeData, _EdgeData], nodelist: Collection[_Node] | None = None, weight: str | None = None ) -> Array2D[np.float64]: ... diff --git a/stubs/networkx/networkx/linalg/spectrum.pyi b/stubs/networkx/networkx/linalg/spectrum.pyi index 05e4455eb7da..a585be518b94 100644 --- a/stubs/networkx/networkx/linalg/spectrum.pyi +++ b/stubs/networkx/networkx/linalg/spectrum.pyi @@ -1,6 +1,6 @@ import numpy as np from networkx._typing import Array1D -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = [ @@ -12,12 +12,14 @@ __all__ = [ ] @_dispatchable -def laplacian_spectrum(G: Graph[_Node], weight: str | None = "weight") -> Array1D[np.float64]: ... +def laplacian_spectrum(G: Graph[_Node, _NodeData, _EdgeData], weight: str | None = "weight") -> Array1D[np.float64]: ... @_dispatchable -def normalized_laplacian_spectrum(G: Graph[_Node], weight: str | None = "weight") -> Array1D[np.float64]: ... +def normalized_laplacian_spectrum( + G: Graph[_Node, _NodeData, _EdgeData], weight: str | None = "weight" +) -> Array1D[np.float64]: ... @_dispatchable -def adjacency_spectrum(G: Graph[_Node], weight: str | None = "weight") -> Array1D[np.complex128]: ... +def adjacency_spectrum(G: Graph[_Node, _NodeData, _EdgeData], weight: str | None = "weight") -> Array1D[np.complex128]: ... @_dispatchable -def modularity_spectrum(G: Graph[_Node]) -> Array1D[np.complex128]: ... +def modularity_spectrum(G: Graph[_Node, _NodeData, _EdgeData]) -> Array1D[np.complex128]: ... @_dispatchable -def bethe_hessian_spectrum(G: Graph[_Node], r: float | None = None) -> Array1D[np.float64]: ... +def bethe_hessian_spectrum(G: Graph[_Node, _NodeData, _EdgeData], r: float | None = None) -> Array1D[np.float64]: ... diff --git a/stubs/networkx/networkx/readwrite/adjlist.pyi b/stubs/networkx/networkx/readwrite/adjlist.pyi index f416e8f891f4..aab1eb11183e 100644 --- a/stubs/networkx/networkx/readwrite/adjlist.pyi +++ b/stubs/networkx/networkx/readwrite/adjlist.pyi @@ -1,14 +1,18 @@ from _typeshed import Incomplete, StrPath, SupportsRead, SupportsWrite from collections.abc import Generator, Iterable -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = ["generate_adjlist", "write_adjlist", "parse_adjlist", "read_adjlist"] -def generate_adjlist(G: Graph[_Node], delimiter: str = " ") -> Generator[str]: ... +def generate_adjlist(G: Graph[_Node, _NodeData, _EdgeData], delimiter: str = " ") -> Generator[str]: ... def write_adjlist( - G: Graph[_Node], path: StrPath | SupportsWrite[bytes], comments: str = "#", delimiter: str = " ", encoding: str = "utf-8" + G: Graph[_Node, _NodeData, _EdgeData], + path: StrPath | SupportsWrite[bytes], + comments: str = "#", + delimiter: str = " ", + encoding: str = "utf-8", ) -> None: ... @_dispatchable def parse_adjlist( diff --git a/stubs/networkx/networkx/readwrite/edgelist.pyi b/stubs/networkx/networkx/readwrite/edgelist.pyi index 8c2983fc3efc..6e9e91cf0312 100644 --- a/stubs/networkx/networkx/readwrite/edgelist.pyi +++ b/stubs/networkx/networkx/readwrite/edgelist.pyi @@ -1,7 +1,7 @@ from _typeshed import Incomplete, StrPath, SupportsRead, SupportsWrite from collections.abc import Generator, Iterable -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = [ @@ -13,9 +13,11 @@ __all__ = [ "write_weighted_edgelist", ] -def generate_edgelist(G: Graph[_Node], delimiter: str = " ", data: bool = True) -> Generator[Incomplete]: ... +def generate_edgelist( + G: Graph[_Node, _NodeData, _EdgeData], delimiter: str = " ", data: bool = True +) -> Generator[Incomplete]: ... def write_edgelist( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], path: StrPath | SupportsWrite[bytes], comments: str = "#", delimiter: str = " ", @@ -43,7 +45,11 @@ def read_edgelist( encoding: str = "utf-8", ) -> Graph[Incomplete]: ... def write_weighted_edgelist( - G: Graph[_Node], path: StrPath | SupportsWrite[bytes], comments: str = "#", delimiter: str = " ", encoding: str = "utf-8" + G: Graph[_Node, _NodeData, _EdgeData], + path: StrPath | SupportsWrite[bytes], + comments: str = "#", + delimiter: str = " ", + encoding: str = "utf-8", ) -> None: ... @_dispatchable def read_weighted_edgelist( diff --git a/stubs/networkx/networkx/readwrite/gexf.pyi b/stubs/networkx/networkx/readwrite/gexf.pyi index bebb998dfe93..282104816e75 100644 --- a/stubs/networkx/networkx/readwrite/gexf.pyi +++ b/stubs/networkx/networkx/readwrite/gexf.pyi @@ -2,20 +2,20 @@ from _typeshed import Incomplete, StrPath, SupportsRead, SupportsWrite from collections.abc import Generator from typing import Final, Literal -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = ["write_gexf", "read_gexf", "relabel_gexf_graph", "generate_gexf"] def write_gexf( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], path: StrPath | SupportsWrite[bytes], encoding: str = "utf-8", prettyprint: bool = True, version: str = "1.2draft", ) -> None: ... def generate_gexf( - G: Graph[_Node], encoding: str = "utf-8", prettyprint: bool = True, version: str = "1.2draft" + G: Graph[_Node, _NodeData, _EdgeData], encoding: str = "utf-8", prettyprint: bool = True, version: str = "1.2draft" ) -> Generator[Incomplete, Incomplete]: ... @_dispatchable def read_gexf( @@ -49,9 +49,9 @@ class GEXFWriter(GEXF): attr: Incomplete def __init__(self, graph=None, encoding: str = "utf-8", prettyprint: bool = True, version: str = "1.2draft") -> None: ... graph_element: Incomplete - def add_graph(self, G: Graph[_Node]) -> None: ... - def add_nodes(self, G: Graph[_Node], graph_element) -> None: ... - def add_edges(self, G: Graph[_Node], graph_element) -> None: ... + def add_graph(self, G: Graph[_Node, _NodeData, _EdgeData]) -> None: ... + def add_nodes(self, G: Graph[_Node, _NodeData, _EdgeData], graph_element) -> None: ... + def add_edges(self, G: Graph[_Node, _NodeData, _EdgeData], graph_element) -> None: ... def add_attributes(self, node_or_edge, xml_obj, data, default): ... def get_attr_id(self, title, attr_type, edge_or_node, default, mode): ... def add_viz(self, element, node_data): ... @@ -70,14 +70,14 @@ class GEXFReader(GEXF): def __call__(self, stream): ... timeformat: Incomplete def make_graph(self, graph_xml): ... - def add_node(self, G: Graph[_Node], node_xml, node_attr, node_pid=None) -> None: ... + def add_node(self, G: Graph[_Node, _NodeData, _EdgeData], node_xml, node_attr, node_pid=None) -> None: ... def add_start_end(self, data, xml): ... def add_viz(self, data, node_xml): ... def add_parents(self, data, node_xml): ... def add_slices(self, data, node_or_edge_xml): ... def add_spells(self, data, node_or_edge_xml): ... - def add_edge(self, G: Graph[_Node], edge_element, edge_attr) -> None: ... + def add_edge(self, G: Graph[_Node, _NodeData, _EdgeData], edge_element, edge_attr) -> None: ... def decode_attr_elements(self, gexf_keys, obj_xml): ... def find_gexf_attributes(self, attributes_element): ... -def relabel_gexf_graph(G: Graph[_Node]) -> Graph[Incomplete]: ... +def relabel_gexf_graph(G: Graph[_Node, _NodeData, _EdgeData]) -> Graph[Incomplete]: ... diff --git a/stubs/networkx/networkx/readwrite/gml.pyi b/stubs/networkx/networkx/readwrite/gml.pyi index 3a9e321d4edf..bb80cf6b95f4 100644 --- a/stubs/networkx/networkx/readwrite/gml.pyi +++ b/stubs/networkx/networkx/readwrite/gml.pyi @@ -3,7 +3,7 @@ from collections.abc import Callable, Generator, Iterable from enum import Enum from typing import Final, Generic, NamedTuple, TypeVar -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable _T = TypeVar("_T") @@ -41,7 +41,11 @@ LIST_START_VALUE: Final = "_networkx_list_start" def parse_gml_lines(lines, label, destringizer): ... def literal_stringizer(value) -> str: ... -def generate_gml(G: Graph[_Node], stringizer: Callable[..., Incomplete] | None = None) -> Generator[Incomplete, Incomplete]: ... +def generate_gml( + G: Graph[_Node, _NodeData, _EdgeData], stringizer: Callable[..., Incomplete] | None = None +) -> Generator[Incomplete, Incomplete]: ... def write_gml( - G: Graph[_Node], path: StrPath | SupportsWrite[bytes], stringizer: Callable[..., Incomplete] | None = None + G: Graph[_Node, _NodeData, _EdgeData], + path: StrPath | SupportsWrite[bytes], + stringizer: Callable[..., Incomplete] | None = None, ) -> None: ... diff --git a/stubs/networkx/networkx/readwrite/graph6.pyi b/stubs/networkx/networkx/readwrite/graph6.pyi index 17cd91d94b58..71714338b059 100644 --- a/stubs/networkx/networkx/readwrite/graph6.pyi +++ b/stubs/networkx/networkx/readwrite/graph6.pyi @@ -1,19 +1,24 @@ from _typeshed import Incomplete, StrPath, SupportsRead, SupportsWrite from collections.abc import Iterable -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = ["from_graph6_bytes", "read_graph6", "to_graph6_bytes", "write_graph6"] @_dispatchable def from_graph6_bytes(bytes_in: bytes) -> Graph[Incomplete]: ... -def to_graph6_bytes(G: Graph[_Node], nodes: Iterable[Incomplete] | None = None, header: bool = True): ... +def to_graph6_bytes(G: Graph[_Node, _NodeData, _EdgeData], nodes: Iterable[Incomplete] | None = None, header: bool = True): ... @_dispatchable def read_graph6(path: StrPath | SupportsRead[bytes]) -> Graph[Incomplete]: ... def write_graph6( - G: Graph[_Node], path: StrPath | SupportsWrite[bytes], nodes: Iterable[Incomplete] | None = None, header: bool = True + G: Graph[_Node, _NodeData, _EdgeData], + path: StrPath | SupportsWrite[bytes], + nodes: Iterable[Incomplete] | None = None, + header: bool = True, +): ... +def write_graph6_file( + G: Graph[_Node, _NodeData, _EdgeData], f, nodes: Iterable[Incomplete] | None = None, header: bool = True ): ... -def write_graph6_file(G: Graph[_Node], f, nodes: Iterable[Incomplete] | None = None, header: bool = True): ... def data_to_n(data): ... def n_to_data(n): ... diff --git a/stubs/networkx/networkx/readwrite/graphml.pyi b/stubs/networkx/networkx/readwrite/graphml.pyi index 4beb539a4ca7..1c2ebbc7cae2 100644 --- a/stubs/networkx/networkx/readwrite/graphml.pyi +++ b/stubs/networkx/networkx/readwrite/graphml.pyi @@ -2,7 +2,7 @@ from _typeshed import Incomplete, StrPath, SupportsRead, SupportsWrite from collections.abc import Generator from typing import Final, Literal -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = [ @@ -17,7 +17,7 @@ __all__ = [ ] def write_graphml_xml( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], path: StrPath | SupportsWrite[bytes], encoding: str = "utf-8", prettyprint: bool = True, @@ -26,7 +26,7 @@ def write_graphml_xml( edge_id_from_attribute: str | None = None, ) -> None: ... def write_graphml_lxml( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], path: StrPath | SupportsWrite[bytes], encoding: str = "utf-8", prettyprint: bool = True, @@ -35,7 +35,7 @@ def write_graphml_lxml( edge_id_from_attribute: str | None = None, ): ... def generate_graphml( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], encoding: str = "utf-8", prettyprint: bool = True, named_key_ids: bool = False, @@ -88,9 +88,9 @@ class GraphMLWriter(GraphML): def get_key(self, name, attr_type, scope, default): ... def add_data(self, name, element_type, value, scope: str = "all", default=None): ... def add_attributes(self, scope, xml_obj, data, default) -> None: ... - def add_nodes(self, G: Graph[_Node], graph_element) -> None: ... - def add_edges(self, G: Graph[_Node], graph_element) -> None: ... - def add_graph_element(self, G: Graph[_Node]) -> None: ... + def add_nodes(self, G: Graph[_Node, _NodeData, _EdgeData], graph_element) -> None: ... + def add_edges(self, G: Graph[_Node, _NodeData, _EdgeData], graph_element) -> None: ... + def add_graph_element(self, G: Graph[_Node, _NodeData, _EdgeData]) -> None: ... def add_graphs(self, graph_list) -> None: ... def dump(self, stream) -> None: ... def indent(self, elem, level: int = 0) -> None: ... @@ -119,7 +119,7 @@ class GraphMLWriterLxml(GraphMLWriter): named_key_ids: bool = False, edge_id_from_attribute=None, ) -> None: ... - def add_graph_element(self, G: Graph[_Node]) -> None: ... + def add_graph_element(self, G: Graph[_Node, _NodeData, _EdgeData]) -> None: ... def add_attributes(self, scope, xml_obj, data, default) -> None: ... def dump(self, stream=None) -> None: ... @@ -134,7 +134,7 @@ class GraphMLReader(GraphML): xml: Incomplete def __call__(self, path=None, string=None) -> Generator[Incomplete]: ... def make_graph(self, graph_xml, graphml_keys, defaults, G=None): ... - def add_node(self, G: Graph[_Node], node_xml, graphml_keys, defaults) -> None: ... - def add_edge(self, G: Graph[_Node], edge_element, graphml_keys) -> None: ... + def add_node(self, G: Graph[_Node, _NodeData, _EdgeData], node_xml, graphml_keys, defaults) -> None: ... + def add_edge(self, G: Graph[_Node, _NodeData, _EdgeData], edge_element, graphml_keys) -> None: ... def decode_data_elements(self, graphml_keys, obj_xml): ... def find_graphml_keys(self, graph_element): ... diff --git a/stubs/networkx/networkx/readwrite/json_graph/adjacency.pyi b/stubs/networkx/networkx/readwrite/json_graph/adjacency.pyi index e1728b1cc49f..3d2ff0e488e3 100644 --- a/stubs/networkx/networkx/readwrite/json_graph/adjacency.pyi +++ b/stubs/networkx/networkx/readwrite/json_graph/adjacency.pyi @@ -1,13 +1,15 @@ from _typeshed import Incomplete from typing import Any -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = ["adjacency_data", "adjacency_graph"] # Any: Complex type union -def adjacency_data(G: Graph[_Node], attrs: dict[Incomplete, Incomplete] = {"id": "id", "key": "key"}) -> dict[str, Any]: ... +def adjacency_data( + G: Graph[_Node, _NodeData, _EdgeData], attrs: dict[Incomplete, Incomplete] = {"id": "id", "key": "key"} +) -> dict[str, Any]: ... @_dispatchable def adjacency_graph( data: dict[Incomplete, Incomplete], diff --git a/stubs/networkx/networkx/readwrite/json_graph/cytoscape.pyi b/stubs/networkx/networkx/readwrite/json_graph/cytoscape.pyi index 959ffb3b2ed5..3368d209f0de 100644 --- a/stubs/networkx/networkx/readwrite/json_graph/cytoscape.pyi +++ b/stubs/networkx/networkx/readwrite/json_graph/cytoscape.pyi @@ -1,12 +1,12 @@ from _typeshed import Incomplete from typing import Any -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = ["cytoscape_data", "cytoscape_graph"] # Any: Complex type union -def cytoscape_data(G: Graph[_Node], name: str = "name", ident: str = "id") -> dict[str, Any]: ... +def cytoscape_data(G: Graph[_Node, _NodeData, _EdgeData], name: str = "name", ident: str = "id") -> dict[str, Any]: ... @_dispatchable def cytoscape_graph(data: dict[Incomplete, Incomplete], name: str = "name", ident: str = "id") -> Graph[Incomplete]: ... diff --git a/stubs/networkx/networkx/readwrite/json_graph/node_link.pyi b/stubs/networkx/networkx/readwrite/json_graph/node_link.pyi index 15c7da4e2da3..3f1a75a66f92 100644 --- a/stubs/networkx/networkx/readwrite/json_graph/node_link.pyi +++ b/stubs/networkx/networkx/readwrite/json_graph/node_link.pyi @@ -1,12 +1,12 @@ from _typeshed import Incomplete -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = ["node_link_data", "node_link_graph"] def node_link_data( - G: Graph[_Node], + G: Graph[_Node, _NodeData, _EdgeData], *, source: str = "source", target: str = "target", diff --git a/stubs/networkx/networkx/readwrite/json_graph/tree.pyi b/stubs/networkx/networkx/readwrite/json_graph/tree.pyi index 052e8b5fb2b5..2a0aae44b1db 100644 --- a/stubs/networkx/networkx/readwrite/json_graph/tree.pyi +++ b/stubs/networkx/networkx/readwrite/json_graph/tree.pyi @@ -1,11 +1,13 @@ from _typeshed import Incomplete from networkx.classes.digraph import DiGraph -from networkx.classes.graph import _Node +from networkx.classes.graph import _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = ["tree_data", "tree_graph"] -def tree_data(G: DiGraph[_Node], root, ident: str = "id", children: str = "children") -> dict[Incomplete, Incomplete]: ... +def tree_data( + G: DiGraph[_Node, _NodeData, _EdgeData], root, ident: str = "id", children: str = "children" +) -> dict[Incomplete, Incomplete]: ... @_dispatchable def tree_graph(data: dict[Incomplete, Incomplete], ident: str = "id", children: str = "children") -> DiGraph[Incomplete]: ... diff --git a/stubs/networkx/networkx/readwrite/multiline_adjlist.pyi b/stubs/networkx/networkx/readwrite/multiline_adjlist.pyi index ae269ad60fb1..47ae7ec4e4fe 100644 --- a/stubs/networkx/networkx/readwrite/multiline_adjlist.pyi +++ b/stubs/networkx/networkx/readwrite/multiline_adjlist.pyi @@ -1,14 +1,18 @@ from _typeshed import Incomplete, StrPath, SupportsRead, SupportsWrite from collections.abc import Generator, Iterable -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.utils.backends import _dispatchable __all__ = ["generate_multiline_adjlist", "write_multiline_adjlist", "parse_multiline_adjlist", "read_multiline_adjlist"] -def generate_multiline_adjlist(G: Graph[_Node], delimiter: str = " ") -> Generator[str]: ... +def generate_multiline_adjlist(G: Graph[_Node, _NodeData, _EdgeData], delimiter: str = " ") -> Generator[str]: ... def write_multiline_adjlist( - G: Graph[_Node], path: StrPath | SupportsWrite[bytes], delimiter: str = " ", comments: str = "#", encoding: str = "utf-8" + G: Graph[_Node, _NodeData, _EdgeData], + path: StrPath | SupportsWrite[bytes], + delimiter: str = " ", + comments: str = "#", + encoding: str = "utf-8", ) -> None: ... @_dispatchable def parse_multiline_adjlist( diff --git a/stubs/networkx/networkx/readwrite/p2g.pyi b/stubs/networkx/networkx/readwrite/p2g.pyi index 22d670a68c16..028ffdf7f863 100644 --- a/stubs/networkx/networkx/readwrite/p2g.pyi +++ b/stubs/networkx/networkx/readwrite/p2g.pyi @@ -1,10 +1,10 @@ from _typeshed import Incomplete, StrPath, SupportsRead -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.classes.multidigraph import MultiDiGraph from networkx.utils.backends import _dispatchable -def write_p2g(G: Graph[_Node], path, encoding: str = "utf-8") -> None: ... +def write_p2g(G: Graph[_Node, _NodeData, _EdgeData], path, encoding: str = "utf-8") -> None: ... @_dispatchable def read_p2g(path: StrPath | SupportsRead[str], encoding: str = "utf-8") -> MultiDiGraph[Incomplete]: ... @_dispatchable diff --git a/stubs/networkx/networkx/readwrite/pajek.pyi b/stubs/networkx/networkx/readwrite/pajek.pyi index efc593fb2122..80eb749db1d5 100644 --- a/stubs/networkx/networkx/readwrite/pajek.pyi +++ b/stubs/networkx/networkx/readwrite/pajek.pyi @@ -1,14 +1,14 @@ from _typeshed import Incomplete, StrPath, SupportsRead, SupportsWrite from collections.abc import Generator, Iterable -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.classes.multidigraph import MultiDiGraph from networkx.utils.backends import _dispatchable __all__ = ["read_pajek", "parse_pajek", "generate_pajek", "write_pajek"] -def generate_pajek(G: Graph[_Node]) -> Generator[Incomplete]: ... -def write_pajek(G: Graph[_Node], path: StrPath | SupportsWrite[bytes], encoding: str = "UTF-8") -> None: ... +def generate_pajek(G: Graph[_Node, _NodeData, _EdgeData]) -> Generator[Incomplete]: ... +def write_pajek(G: Graph[_Node, _NodeData, _EdgeData], path: StrPath | SupportsWrite[bytes], encoding: str = "UTF-8") -> None: ... @_dispatchable def read_pajek(path: StrPath | SupportsRead[bytes], encoding: str = "UTF-8") -> MultiDiGraph[Incomplete]: ... @_dispatchable diff --git a/stubs/networkx/networkx/readwrite/sparse6.pyi b/stubs/networkx/networkx/readwrite/sparse6.pyi index 0e65988decab..389aeac9ce6a 100644 --- a/stubs/networkx/networkx/readwrite/sparse6.pyi +++ b/stubs/networkx/networkx/readwrite/sparse6.pyi @@ -1,7 +1,7 @@ from _typeshed import Incomplete, StrPath, SupportsRead, SupportsWrite from collections.abc import Iterable -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData from networkx.classes.multigraph import MultiGraph from networkx.utils.backends import _dispatchable @@ -9,9 +9,12 @@ __all__ = ["from_sparse6_bytes", "read_sparse6", "to_sparse6_bytes", "write_spar @_dispatchable def from_sparse6_bytes(string: str) -> Graph[Incomplete]: ... -def to_sparse6_bytes(G: Graph[_Node], nodes: Iterable[Incomplete] | None = None, header: bool = True): ... +def to_sparse6_bytes(G: Graph[_Node, _NodeData, _EdgeData], nodes: Iterable[Incomplete] | None = None, header: bool = True): ... @_dispatchable def read_sparse6(path: StrPath | SupportsRead[bytes]) -> MultiGraph[Incomplete]: ... def write_sparse6( - G: Graph[_Node], path: StrPath | SupportsWrite[bytes], nodes: Iterable[Incomplete] | None = None, header: bool = True + G: Graph[_Node, _NodeData, _EdgeData], + path: StrPath | SupportsWrite[bytes], + nodes: Iterable[Incomplete] | None = None, + header: bool = True, ) -> None: ... diff --git a/stubs/networkx/networkx/utils/misc.pyi b/stubs/networkx/networkx/utils/misc.pyi index cc14f1bff944..2105dbb73b39 100644 --- a/stubs/networkx/networkx/utils/misc.pyi +++ b/stubs/networkx/networkx/utils/misc.pyi @@ -5,7 +5,7 @@ from types import ModuleType from typing import TypeAlias import numpy -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData __all__ = [ "flatten", @@ -58,4 +58,4 @@ def create_py_random_state(random_state: _RandomState = None): ... def nodes_equal(nodes1, nodes2) -> bool: ... def edges_equal(edges1, edges2, *, directed: bool = False) -> bool: ... def graphs_equal(graph1, graph2) -> bool: ... -def _clear_cache(G: Graph[_Node]) -> None: ... +def _clear_cache(G: Graph[_Node, _NodeData, _EdgeData]) -> None: ... diff --git a/stubs/networkx/networkx/utils/rcm.pyi b/stubs/networkx/networkx/utils/rcm.pyi index 0f4f4ed838e3..5df48ed2b7b3 100644 --- a/stubs/networkx/networkx/utils/rcm.pyi +++ b/stubs/networkx/networkx/utils/rcm.pyi @@ -1,15 +1,15 @@ from _typeshed import Incomplete from collections.abc import Callable, Generator -from networkx.classes.graph import Graph, _Node +from networkx.classes.graph import Graph, _EdgeData, _Node, _NodeData __all__ = ["cuthill_mckee_ordering", "reverse_cuthill_mckee_ordering"] def cuthill_mckee_ordering( - G: Graph[_Node], heuristic: Callable[..., Incomplete] | None = None + G: Graph[_Node, _NodeData, _EdgeData], heuristic: Callable[..., Incomplete] | None = None ) -> Generator[Incomplete, Incomplete]: ... def reverse_cuthill_mckee_ordering( - G: Graph[_Node], heuristic: Callable[..., Incomplete] | None = None + G: Graph[_Node, _NodeData, _EdgeData], heuristic: Callable[..., Incomplete] | None = None ) -> Generator[Incomplete, Incomplete, Incomplete]: ... -def connected_cuthill_mckee_ordering(G: Graph[_Node], heuristic=None): ... -def pseudo_peripheral_node(G: Graph[_Node]): ... +def connected_cuthill_mckee_ordering(G: Graph[_Node, _NodeData, _EdgeData], heuristic=None): ... +def pseudo_peripheral_node(G: Graph[_Node, _NodeData, _EdgeData]): ... From dbcd6239483b9312480fed8d0396dc060666eda1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 11 Sep 2026 19:57:08 +0000 Subject: [PATCH 2/3] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stubs/networkx/@tests/test_cases/check_graph_data_types.py | 1 - stubs/networkx/networkx/classes/function.pyi | 7 +++++++ stubs/networkx/networkx/convert_matrix.pyi | 5 +++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/stubs/networkx/@tests/test_cases/check_graph_data_types.py b/stubs/networkx/@tests/test_cases/check_graph_data_types.py index 84807112f224..3930e3665c7a 100644 --- a/stubs/networkx/@tests/test_cases/check_graph_data_types.py +++ b/stubs/networkx/@tests/test_cases/check_graph_data_types.py @@ -2,7 +2,6 @@ from collections.abc import Iterator, Mapping from typing import Any - from typing_extensions import assert_type import networkx as nx diff --git a/stubs/networkx/networkx/classes/function.pyi b/stubs/networkx/networkx/classes/function.pyi index dc625ef28fc6..691fdccd0d06 100644 --- a/stubs/networkx/networkx/classes/function.pyi +++ b/stubs/networkx/networkx/classes/function.pyi @@ -61,12 +61,14 @@ def number_of_nodes(G: Graph[_Node, _NodeData, _EdgeData]): ... def number_of_edges(G: Graph[_Node, _NodeData, _EdgeData]): ... def density(G: Graph[_Node, _NodeData, _EdgeData]): ... def degree_histogram(G: Graph[_Node, _NodeData, _EdgeData]) -> list[int]: ... + @overload def is_directed(G: PlanarEmbedding[Hashable]) -> Literal[False]: ... # type: ignore[misc] # Incompatible return types @overload def is_directed(G: DiGraph[Hashable]) -> Literal[True]: ... # type: ignore[misc] # Incompatible return types @overload def is_directed(G: Graph[Hashable]) -> Literal[False]: ... + def freeze(G: Graph[_Node, _NodeData, _EdgeData]): ... def is_frozen(G: Graph[Incomplete]) -> bool: ... def add_star(G_to_add_to: Graph[Incomplete], nodes_for_star: Iterable[Incomplete], **attr) -> None: ... @@ -101,10 +103,12 @@ def set_node_attributes( backend=None, **backend_kwargs, ) -> None: ... + @_dispatchable def get_node_attributes(G: Graph[_Node, _NodeData, _EdgeData], name: str, default=None) -> dict[_Node, Incomplete]: ... @_dispatchable def remove_node_attributes(G: Graph[_Node, _NodeData, _EdgeData], *attr_names, nbunch=None) -> None: ... + @overload def set_edge_attributes( G: Graph[_Node, _NodeData, _EdgeData], @@ -127,6 +131,7 @@ def set_edge_attributes( def set_edge_attributes( G: Graph[Hashable], values, name: None = None, *, backend: str | None = None, **backend_kwargs ) -> None: ... + @_dispatchable def get_edge_attributes( G: Graph[_Node, _NodeData, _EdgeData], name: str, default=None @@ -148,6 +153,7 @@ def is_negatively_weighted( @_dispatchable def is_empty(G: Graph[Hashable]) -> bool: ... def nodes_with_selfloops(G: Graph[_Node, _NodeData, _EdgeData]) -> Generator[_Node]: ... + @overload def selfloop_edges( G: Graph[_Node, _NodeData, _EdgeData], data: Literal[False] = False, keys: Literal[False] = False, default=None @@ -176,6 +182,7 @@ def selfloop_edges( def selfloop_edges( G: Graph[_Node, Any, Any], data: str, keys: Literal[True], default: _U | None = None ) -> Generator[tuple[_Node, _Node, int, _U]]: ... + @_dispatchable def number_of_selfloops(G: Graph[Hashable]) -> int: ... def is_path(G: Graph[_Node, _NodeData, _EdgeData], path: Iterable[Incomplete]) -> bool: ... diff --git a/stubs/networkx/networkx/convert_matrix.pyi b/stubs/networkx/networkx/convert_matrix.pyi index bde3ba304f64..f83f4470f30f 100644 --- a/stubs/networkx/networkx/convert_matrix.pyi +++ b/stubs/networkx/networkx/convert_matrix.pyi @@ -38,10 +38,12 @@ def to_pandas_adjacency( weight: str = "weight", nonedge: float = 0.0, ) -> _DataFrame: ... + @overload def from_pandas_adjacency(df: _DataFrame, create_using: type[_G]) -> _G: ... @overload def from_pandas_adjacency(df: _DataFrame, create_using: None = None) -> Graph[Incomplete]: ... + @_dispatchable def to_pandas_edgelist( G: Graph[_Node, _NodeData, _EdgeData], @@ -51,6 +53,7 @@ def to_pandas_edgelist( dtype: _ExtensionDtype | None = None, edge_key: str | int | None = None, ) -> _DataFrame: ... + @overload def from_pandas_edgelist( df: _DataFrame, @@ -79,6 +82,7 @@ def from_pandas_edgelist( create_using: None = None, edge_key: str | None = None, ) -> Graph[Incomplete]: ... + @_dispatchable def to_scipy_sparse_array( G: Graph[_Node, _NodeData, _EdgeData], @@ -104,6 +108,7 @@ def to_numpy_array( weight: str = "weight", nonedge: float = 0.0, ) -> numpy.ndarray[Incomplete, numpy.dtype[Incomplete]]: ... + @overload def from_numpy_array( A: numpy.ndarray[Incomplete, Incomplete], parallel_edges: bool = False, create_using: None = None From 3c6e30819495d685fc21fff6cbe2a8e2e04d093b Mon Sep 17 00:00:00 2001 From: ANSHUL SINGH <72524975+ekanshul@users.noreply.github.com> Date: Sat, 12 Sep 2026 01:38:59 +0530 Subject: [PATCH 3/3] Restrict the test case to Python 3.12+ and to fully annotated functions The other networkx test cases carry the -py312 suffix because numpy's stubs no longer type-check under --python-version 3.10/3.11, and the strict test-case pyright config reports partially unknown types for functions whose return is unannotated or typed with scipy. Co-Authored-By: Claude Fable 5.1 --- ...k_graph_data_types.py => check_graph_data_types-py312.py} | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) rename stubs/networkx/@tests/test_cases/{check_graph_data_types.py => check_graph_data_types-py312.py} (94%) diff --git a/stubs/networkx/@tests/test_cases/check_graph_data_types.py b/stubs/networkx/@tests/test_cases/check_graph_data_types-py312.py similarity index 94% rename from stubs/networkx/@tests/test_cases/check_graph_data_types.py rename to stubs/networkx/@tests/test_cases/check_graph_data_types-py312.py index 3930e3665c7a..6437664376cf 100644 --- a/stubs/networkx/@tests/test_cases/check_graph_data_types.py +++ b/stubs/networkx/@tests/test_cases/check_graph_data_types-py312.py @@ -20,16 +20,15 @@ def __len__(self) -> int: ... assert_type(nx.degree_histogram(G), list[int]) assert_type(nx.to_dict_of_lists(G), dict[int, list[int]]) assert_type(nx.is_weighted(G), bool) -nx.number_of_nodes(G) +assert_type(nx.is_negatively_weighted(G), bool) nx.write_gml(G, "graph.gml") nx.generate_adjlist(G) nx.node_link_data(G) -nx.adjacency_matrix(G) nx.laplacian_spectrum(G) reverse_cuthill_mckee_ordering(G) D = nx.DiGraph[str, NodeData, NodeData]() -nx.number_of_edges(D) +assert_type(nx.is_weighted(D), bool) nx.write_edgelist(D, "graph.edgelist") nx.directed_laplacian_matrix(D)