From 93784bdafec552e5d2b2dd382f0ab81c192481f8 Mon Sep 17 00:00:00 2001 From: Hunter Hogan Date: Fri, 15 Aug 2025 22:56:46 -0500 Subject: [PATCH 1/5] complete networkx/...lowest_common_ancestors.pyi addresses #14499 follows #14509, #14569 added TypeVar for parameter `default ` to class Graph: mirroring class MultiGraph --- .../algorithms/lowest_common_ancestors.pyi | 18 ++++++++++++------ stubs/networkx/networkx/classes/graph.pyi | 3 ++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi b/stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi index ab7a8e5472cd..a27a112c3378 100644 --- a/stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi +++ b/stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi @@ -1,17 +1,23 @@ -from _typeshed import Incomplete -from collections.abc import Generator +from collections.abc import Generator, Iterable +from typing_extensions import TypeVar from networkx.classes.digraph import DiGraph from networkx.classes.graph import _Node from networkx.utils.backends import _dispatchable +_DefaultT = TypeVar("_DefaultT") + __all__ = ["all_pairs_lowest_common_ancestor", "tree_all_pairs_lowest_common_ancestor", "lowest_common_ancestor"] @_dispatchable -def all_pairs_lowest_common_ancestor(G: DiGraph[_Node], pairs=None): ... +def all_pairs_lowest_common_ancestor( + G: DiGraph[_Node], pairs: Iterable[tuple[_Node, _Node]] | None = None +) -> Generator[tuple[tuple[_Node, _Node], _Node | None], None, None]: ... @_dispatchable -def lowest_common_ancestor(G: DiGraph[_Node], node1, node2, default=None): ... +def lowest_common_ancestor( + G: DiGraph[_Node], node1: _Node, node2: _Node, default: _DefaultT | None = None +) -> _Node | _DefaultT: ... @_dispatchable def tree_all_pairs_lowest_common_ancestor( - G: DiGraph[_Node], root: _Node | None = None, pairs=None -) -> Generator[Incomplete, None, None]: ... + G: DiGraph[_Node], root: _Node | None = None, pairs: Iterable[tuple[_Node, _Node]] | None = None +) -> Generator[tuple[tuple[_Node, _Node], _Node], None, None]: ... diff --git a/stubs/networkx/networkx/classes/graph.pyi b/stubs/networkx/networkx/classes/graph.pyi index ffdab103eaad..7e0c12049c75 100644 --- a/stubs/networkx/networkx/classes/graph.pyi +++ b/stubs/networkx/networkx/classes/graph.pyi @@ -8,6 +8,7 @@ from networkx.classes.coreviews import AdjacencyView, AtlasView from networkx.classes.digraph import DiGraph from networkx.classes.reportviews import DegreeView, EdgeView, NodeView +_DefaultT = TypeVar("_DefaultT") _Node = TypeVar("_Node", bound=Hashable) _NodeWithData: TypeAlias = tuple[_Node, dict[str, Any]] _NodePlus: TypeAlias = _Node | _NodeWithData[_Node] @@ -82,7 +83,7 @@ class Graph(Collection[_Node]): def neighbors(self, n: _Node) -> Iterator[_Node]: ... @cached_property def edges(self) -> EdgeView[_Node]: ... - def get_edge_data(self, u: _Node, v: _Node, default: Any = None) -> dict[str, Any]: ... + def get_edge_data(self, u: _Node, v: _Node, default: _DefaultT | None = None) -> dict[str, Any] | _DefaultT: ... # default: any Python object def adjacency(self) -> Iterator[tuple[_Node, dict[_Node, dict[str, Any]]]]: ... @cached_property From dac749a7c3dbc920dc31f3098221745342e093ae Mon Sep 17 00:00:00 2001 From: Hunter Hogan Date: Mon, 18 Aug 2025 16:07:50 -0500 Subject: [PATCH 2/5] Update stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi Co-authored-by: Sebastian Rittau --- stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi b/stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi index a27a112c3378..a28ddcd67a6f 100644 --- a/stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi +++ b/stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi @@ -12,7 +12,7 @@ __all__ = ["all_pairs_lowest_common_ancestor", "tree_all_pairs_lowest_common_anc @_dispatchable def all_pairs_lowest_common_ancestor( G: DiGraph[_Node], pairs: Iterable[tuple[_Node, _Node]] | None = None -) -> Generator[tuple[tuple[_Node, _Node], _Node | None], None, None]: ... +) -> Generator[tuple[tuple[_Node, _Node], _Node | None]]: ... @_dispatchable def lowest_common_ancestor( G: DiGraph[_Node], node1: _Node, node2: _Node, default: _DefaultT | None = None From 5d724801fc23b6c7779c9625cd57210151916793 Mon Sep 17 00:00:00 2001 From: Hunter Hogan Date: Mon, 18 Aug 2025 16:08:35 -0500 Subject: [PATCH 3/5] Update stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi Co-authored-by: Sebastian Rittau --- stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi b/stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi index a28ddcd67a6f..4bd34052d74d 100644 --- a/stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi +++ b/stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi @@ -20,4 +20,4 @@ def lowest_common_ancestor( @_dispatchable def tree_all_pairs_lowest_common_ancestor( G: DiGraph[_Node], root: _Node | None = None, pairs: Iterable[tuple[_Node, _Node]] | None = None -) -> Generator[tuple[tuple[_Node, _Node], _Node], None, None]: ... +) -> Generator[tuple[tuple[_Node, _Node], _Node]]: ... From 8f6140d236e253f1bceeadaac5cc862a8b78af99 Mon Sep 17 00:00:00 2001 From: Hunter Hogan Date: Mon, 18 Aug 2025 18:29:11 -0500 Subject: [PATCH 4/5] networkx: overload + TypeVar --- stubs/networkx/networkx/classes/graph.pyi | 5 ++++- .../networkx/networkx/classes/multigraph.pyi | 19 +++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/stubs/networkx/networkx/classes/graph.pyi b/stubs/networkx/networkx/classes/graph.pyi index 7e0c12049c75..6335078252b1 100644 --- a/stubs/networkx/networkx/classes/graph.pyi +++ b/stubs/networkx/networkx/classes/graph.pyi @@ -83,7 +83,10 @@ class Graph(Collection[_Node]): def neighbors(self, n: _Node) -> Iterator[_Node]: ... @cached_property def edges(self) -> EdgeView[_Node]: ... - def get_edge_data(self, u: _Node, v: _Node, default: _DefaultT | None = None) -> dict[str, Any] | _DefaultT: ... + @overload + def get_edge_data(self, u: _Node, v: _Node, default: None = None) -> dict[str, Any] | None: ... + @overload + def get_edge_data(self, u: _Node, v: _Node, default: _DefaultT) -> dict[str, Any] | _DefaultT: ... # default: any Python object def adjacency(self) -> Iterator[tuple[_Node, dict[_Node, dict[str, Any]]]]: ... @cached_property diff --git a/stubs/networkx/networkx/classes/multigraph.pyi b/stubs/networkx/networkx/classes/multigraph.pyi index d0bb1ef27c82..dc40c4e868a9 100644 --- a/stubs/networkx/networkx/classes/multigraph.pyi +++ b/stubs/networkx/networkx/classes/multigraph.pyi @@ -29,18 +29,25 @@ class MultiGraph(Graph[_Node]): def remove_edge(self, u: _Node, v: _Node, key: Hashable | None = None) -> None: ... def has_edge(self, u: _Node, v: _Node, key: Hashable | None = None) -> bool: ... @overload # type: ignore[override] - def get_edge_data( - self, u: _Node, v: _Node, key: Hashable, default: _DefaultT | None = None - ) -> dict[str, Any] | _DefaultT: ... + def get_edge_data(self, u: _Node, v: _Node, key: Hashable, default: None = None) -> dict[str, Any] | None: ... + # key : hashable identifier, optional (default=None). + # Returns : The edge attribute dictionary. + @overload # type: ignore[override] + def get_edge_data(self, u: _Node, v: _Node, key: Hashable, default: _DefaultT) -> dict[str, Any] | _DefaultT: ... # key : hashable identifier, optional (default=None). # default : any Python object (default=None). Value to return if the specific edge (u, v, key) is not found. - # Returns: The edge attribute dictionary. + # Returns : The edge attribute dictionary. + @overload + def get_edge_data( + self, u: _Node, v: _Node, key: None = None, default: None = None + ) -> dict[Hashable, dict[str, Any] | None]: ... + # Returns : A dictionary mapping edge keys to attribute dictionaries for each of those edges if no specific key is provided. @overload def get_edge_data( - self, u: _Node, v: _Node, key: None = None, default: _DefaultT | None = None + self, u: _Node, v: _Node, key: None = None, *, default: _DefaultT ) -> dict[Hashable, dict[str, Any] | _DefaultT]: ... # default : any Python object (default=None). Value to return if there are no edges between u and v and no key is specified. - # Returns: A dictionary mapping edge keys to attribute dictionaries for each of those edges if no specific key is provided. + # Returns : A dictionary mapping edge keys to attribute dictionaries for each of those edges if no specific key is provided. def copy(self, as_view: bool = False) -> MultiGraph[_Node]: ... def to_directed(self, as_view: bool = False) -> MultiDiGraph[_Node]: ... def to_undirected(self, as_view: bool = False) -> MultiGraph[_Node]: ... From 906dd82ed92eaf3653b6809efde3e60f73fdbcba Mon Sep 17 00:00:00 2001 From: Hunter Hogan Date: Mon, 18 Aug 2025 19:14:14 -0500 Subject: [PATCH 5/5] networkx: overload + TypeVar, but error. I tried a few things, nothing helped. I thought adding `networkx\.(algorithms\.)?(lowest_common_ancestors\.)?lowest_common_ancestor` to https://github.com/python/typeshed/blob/d270bb0dc1df3fcfae2808c9a5a0f7ec802e1fb2/stubs/networkx/%40tests/stubtest_allowlist.txt#L1-L11 would resolve the problem, but it didn't. --- .../networkx/algorithms/lowest_common_ancestors.pyi | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi b/stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi index 4bd34052d74d..7de4949ccb7d 100644 --- a/stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi +++ b/stubs/networkx/networkx/algorithms/lowest_common_ancestors.pyi @@ -1,4 +1,5 @@ from collections.abc import Generator, Iterable +from typing import overload from typing_extensions import TypeVar from networkx.classes.digraph import DiGraph @@ -13,10 +14,12 @@ __all__ = ["all_pairs_lowest_common_ancestor", "tree_all_pairs_lowest_common_anc def all_pairs_lowest_common_ancestor( G: DiGraph[_Node], pairs: Iterable[tuple[_Node, _Node]] | None = None ) -> Generator[tuple[tuple[_Node, _Node], _Node | None]]: ... +@overload @_dispatchable -def lowest_common_ancestor( - G: DiGraph[_Node], node1: _Node, node2: _Node, default: _DefaultT | None = None -) -> _Node | _DefaultT: ... +def lowest_common_ancestor(G: DiGraph[_Node], node1: _Node, node2: _Node, default: None = None) -> _Node | None: ... +@overload +@_dispatchable +def lowest_common_ancestor(G: DiGraph[_Node], node1: _Node, node2: _Node, default: _DefaultT) -> _Node | _DefaultT: ... @_dispatchable def tree_all_pairs_lowest_common_ancestor( G: DiGraph[_Node], root: _Node | None = None, pairs: Iterable[tuple[_Node, _Node]] | None = None