Skip to content

networkx: ignore_missing_stub = false #13968

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions stubs/networkx/@tests/stubtest_allowlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,17 @@ networkx\.algorithms\.bipartite\.(cluster\.)?clustering
# failing to account for explicitly passing in the default value."
# Which is true, but would require some way of concatenating `backend` to ParamSpec.kwargs
networkx\.(utils\.)?(backends\.)?_dispatchable\.__call__

# Tests are excluded
networkx.conftest
networkx(\..+?)?\.tests(\..+?)?

# "..._DT is not present at runtime" but we don't set it in stubs, I don't understand this one
networkx(\.algorithms)?(\.tree)?(\.mst)?\.SpanningTreeIterator\.Partition\._DT
networkx(\.algorithms)?(\.tree)?(\.branchings)?\.ArborescenceIterator\.Partition\._DT

# variable differs from runtime type abc.ABCMeta
networkx.classes.reportviews.EdgeView.dataview
networkx.classes.reportviews.InEdgeView.dataview
networkx.classes.reportviews.OutEdgeView.dataview
networkx.classes.reportviews.OutMultiEdgeView.dataview
Comment on lines +38 to +46
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two issues I don't understand. I'm not sure if it's something I should do differently, just ignore, and/or report to mypy/stubtest

4 changes: 2 additions & 2 deletions stubs/networkx/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ version = "3.4.2"
upstream_repository = "https://github.com/networkx/networkx"
# requires a version of numpy with a `py.typed` file
requires = ["numpy>=1.20"]
partial_stub = true
# Uses more recent dataclass kwargs
requires_python = ">=3.10"

[tool.stubtest]
ignore_missing_stub = true
# stub_uploader won't allow pandas-stubs in the requires field https://github.com/typeshed-internal/stub_uploader/issues/90
stubtest_requirements = ["pandas"]
1 change: 1 addition & 0 deletions stubs/networkx/networkx/algorithms/planarity.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class PlanarEmbedding(DiGraph[_Node]):
def get_data(self) -> dict[_Node, list[_Node]]: ...
def set_data(self, data: Mapping[_Node, Reversible[_Node]]) -> None: ...
def neighbors_cw_order(self, v: _Node) -> Generator[_Node, None, None]: ...
def add_half_edge(self, start_node: _Node, end_node: _Node, *, cw: _Node | None = None, ccw: _Node | None = None): ...
def check_structure(self) -> None: ...
def add_half_edge_ccw(self, start_node: _Node, end_node: _Node, reference_neighbor: _Node) -> None: ...
def add_half_edge_cw(self, start_node: _Node, end_node: _Node, reference_neighbor: _Node) -> None: ...
Expand Down
3 changes: 2 additions & 1 deletion stubs/networkx/networkx/algorithms/tree/branchings.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ def minimum_spanning_arborescence(
): ...

class ArborescenceIterator:
@dataclass
@dataclass(order=True)
class Partition:
mst_weight: float
partition_dict: dict[Incomplete, Incomplete]
def __copy__(self) -> ArborescenceIterator.Partition: ...

G: Incomplete
weight: Incomplete
Expand Down
3 changes: 2 additions & 1 deletion stubs/networkx/networkx/algorithms/tree/mst.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,11 @@ def random_spanning_tree(
): ...

class SpanningTreeIterator:
@dataclass
@dataclass(order=True)
class Partition:
mst_weight: float
partition_dict: dict[Incomplete, Incomplete]
def __copy__(self) -> SpanningTreeIterator.Partition: ...

G: Incomplete
weight: Incomplete
Expand Down
13 changes: 7 additions & 6 deletions stubs/networkx/networkx/classes/graph.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,13 @@ _Data: TypeAlias = (
__all__ = ["Graph"]

class Graph(Collection[_Node]):
node_dict_factory: ClassVar[_MapFactory] = ...
node_attr_dict_factory: ClassVar[_MapFactory] = ...
adjlist_outer_dict_factory: ClassVar[_MapFactory] = ...
adjlist_inner_dict_factory: ClassVar[_MapFactory] = ...
edge_attr_dict_factory: ClassVar[_MapFactory] = ...
graph_attr_dict_factory: ClassVar[_MapFactory] = ...
__networkx_backend__: ClassVar[str]
node_dict_factory: ClassVar[_MapFactory]
node_attr_dict_factory: ClassVar[_MapFactory]
adjlist_outer_dict_factory: ClassVar[_MapFactory]
adjlist_inner_dict_factory: ClassVar[_MapFactory]
edge_attr_dict_factory: ClassVar[_MapFactory]
graph_attr_dict_factory: ClassVar[_MapFactory]

graph: dict[str, Any]

Expand Down
4 changes: 3 additions & 1 deletion stubs/networkx/networkx/classes/multigraph.pyi
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from _typeshed import Incomplete
from functools import cached_property
from typing import ClassVar
from typing_extensions import TypeAlias

from networkx.classes.coreviews import MultiAdjacencyView
from networkx.classes.graph import Graph, _Node
from networkx.classes.graph import Graph, _MapFactory, _Node
from networkx.classes.multidigraph import MultiDiGraph
from networkx.classes.reportviews import OutMultiEdgeView

Expand All @@ -12,6 +13,7 @@ _MultiEdge: TypeAlias = tuple[_Node, _Node, int] # noqa: Y047
__all__ = ["MultiGraph"]

class MultiGraph(Graph[_Node]):
edge_key_dict_factory: ClassVar[_MapFactory]
def __init__(self, incoming_graph_data: Incomplete | None = None, multigraph_input: bool | None = None, **attr) -> None: ...
@cached_property
def adj(self) -> MultiAdjacencyView[_Node, _Node, dict[str, Incomplete]]: ...
Expand Down
203 changes: 198 additions & 5 deletions stubs/networkx/networkx/classes/reportviews.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -85,19 +85,21 @@ class EdgeDataView(OutEdgeDataView[_Node, _D]): ...
class InEdgeDataView(OutEdgeDataView[_Node, _D]): ...

class OutMultiEdgeDataView(OutEdgeDataView[_Node, _D]):
keys: bool
def __init__(
self, viewer, nbunch: _NBunch[_Node] = None, data: bool = False, *, default: Incomplete | None = None, keys: bool = False
) -> None: ...

class MultiEdgeDataView(OutEdgeDataView[_Node, _D]): ...
class InMultiEdgeDataView(OutEdgeDataView[_Node, _D]): ...

class OutEdgeView(AbstractSet[Incomplete], Mapping[Incomplete, Incomplete], Generic[_Node]):
class OutEdgeView(AbstractSet[Incomplete], Mapping[Incomplete, Incomplete], EdgeViewABC, Generic[_Node]):
def __init__(self, G: Graph[_Node]) -> None: ...
def __len__(self) -> int: ...
def __iter__(self) -> Iterator[tuple[_Node, _Node]]: ...
def __contains__(self, e: _Edge[_Node]) -> bool: ... # type: ignore[override]
def __getitem__(self, e: _Edge[_Node]) -> dict[str, Any]: ...
dataview = OutEdgeDataView
@overload
def __call__(self, nbunch: None = None, data: Literal[False] = False, *, default: Unused = None) -> Self: ... # type: ignore[overload-overlap]
@overload
Expand Down Expand Up @@ -131,12 +133,82 @@ class OutEdgeView(AbstractSet[Incomplete], Mapping[Incomplete, Incomplete], Gene
self, data: str, default: _U | None = None, nbunch: _NBunch[_Node] = None
) -> OutEdgeDataView[_Node, tuple[_Node, _Node, _U]]: ...

class EdgeView(OutEdgeView[_Node]): ...
class InEdgeView(OutEdgeView[_Node]): ...
class EdgeView(OutEdgeView[_Node]):
dataview = EdgeDataView
# Have to override parent's overloads with the proper return type based on dataview
@overload
def __call__(self, nbunch: None = None, data: Literal[False] = False, *, default: Unused = None) -> Self: ... # type: ignore[overload-overlap]
@overload
def __call__(
self, nbunch: _Node | Iterable[_Node], data: Literal[False] = False, *, default: None = None
) -> EdgeDataView[_Node, tuple[_Node, _Node]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node], data: Literal[True], *, default: None = None
) -> EdgeDataView[_Node, tuple[_Node, _Node, dict[str, Incomplete]]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node] = None, *, data: Literal[True], default: None = None
) -> EdgeDataView[_Node, tuple[_Node, _Node, dict[str, Incomplete]]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node], data: str, *, default: _U | None = None
) -> EdgeDataView[_Node, tuple[_Node, _Node, _U]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node] = None, *, data: str, default: _U | None = None
) -> EdgeDataView[_Node, tuple[_Node, _Node, _U]]: ...
@overload
def data(self, data: Literal[False], default: Unused = None, nbunch: None = None) -> Self: ...
@overload
def data(
self, data: Literal[True] = True, default: None = None, nbunch: _NBunch[_Node] = None
) -> EdgeDataView[_Node, tuple[_Node, _Node, dict[str, Incomplete]]]: ...
@overload
def data(
self, data: str, default: _U | None = None, nbunch: _NBunch[_Node] = None
) -> EdgeDataView[_Node, tuple[_Node, _Node, _U]]: ...

class InEdgeView(OutEdgeView[_Node]):
dataview = InEdgeDataView
# Have to override parent's overloads with the proper return type based on dataview
@overload
def __call__(self, nbunch: None = None, data: Literal[False] = False, *, default: Unused = None) -> Self: ... # type: ignore[overload-overlap]
@overload
def __call__(
self, nbunch: _Node | Iterable[_Node], data: Literal[False] = False, *, default: None = None
) -> InEdgeDataView[_Node, tuple[_Node, _Node]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node], data: Literal[True], *, default: None = None
) -> InEdgeDataView[_Node, tuple[_Node, _Node, dict[str, Incomplete]]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node] = None, *, data: Literal[True], default: None = None
) -> InEdgeDataView[_Node, tuple[_Node, _Node, dict[str, Incomplete]]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node], data: str, *, default: _U | None = None
) -> InEdgeDataView[_Node, tuple[_Node, _Node, _U]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node] = None, *, data: str, default: _U | None = None
) -> InEdgeDataView[_Node, tuple[_Node, _Node, _U]]: ...
@overload
def data(self, data: Literal[False], default: Unused = None, nbunch: None = None) -> Self: ...
@overload
def data(
self, data: Literal[True] = True, default: None = None, nbunch: _NBunch[_Node] = None
) -> InEdgeDataView[_Node, tuple[_Node, _Node, dict[str, Incomplete]]]: ...
@overload
def data(
self, data: str, default: _U | None = None, nbunch: _NBunch[_Node] = None
) -> InEdgeDataView[_Node, tuple[_Node, _Node, _U]]: ...

class OutMultiEdgeView(OutEdgeView[_Node]):
def __iter__(self) -> Iterator[tuple[_Node, _Node, Incomplete]]: ... # type: ignore[override]
def __getitem__(self, e: tuple[_Node, _Node, Incomplete]) -> dict[str, Any]: ... # type: ignore[override]
dataview = OutMultiEdgeDataView
@overload # type: ignore[override] # Has an additional `keys` keyword argument
def __call__( # type: ignore[overload-overlap]
self, nbunch: None = None, data: Literal[False] = False, *, default: Unused = None, keys: Literal[True]
Expand Down Expand Up @@ -196,5 +268,126 @@ class OutMultiEdgeView(OutEdgeView[_Node]):
self, data: str, default: _U | None = None, nbunch: _NBunch[_Node] = None, *, keys: Literal[True]
) -> OutMultiEdgeDataView[_Node, tuple[_Node, _Node, Incomplete, _U]]: ...

class MultiEdgeView(OutMultiEdgeView[_Node]): ...
class InMultiEdgeView(OutMultiEdgeView[_Node]): ...
class MultiEdgeView(OutMultiEdgeView[_Node]):
dataview = MultiEdgeDataView # type: ignore[assignment]
# Have to override parent's overloads with the proper return type based on dataview
@overload # type: ignore[override] # Has an additional `keys` keyword argument
def __call__( # type: ignore[overload-overlap]
self, nbunch: None = None, data: Literal[False] = False, *, default: Unused = None, keys: Literal[True]
) -> Self: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node] = None, data: Literal[False] = False, *, default: None = None, keys: Literal[False] = False
) -> MultiEdgeDataView[_Node, tuple[_Node, _Node]]: ...
@overload
def __call__(
self, nbunch: _Node | Iterable[_Node], data: Literal[False] = False, *, default: None = None, keys: Literal[True]
) -> MultiEdgeDataView[_Node, tuple[_Node, _Node, Incomplete]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node] = None, *, data: Literal[True], default: None = None, keys: Literal[True]
) -> MultiEdgeDataView[_Node, tuple[_Node, _Node, Incomplete, dict[str, Incomplete]]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node], data: Literal[True], *, default: None = None, keys: Literal[True]
) -> MultiEdgeDataView[_Node, tuple[_Node, _Node, Incomplete, dict[str, Incomplete]]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node] = None, *, data: Literal[True], default: None = None, keys: Literal[False] = False
) -> MultiEdgeDataView[_Node, tuple[_Node, _Node, dict[str, Incomplete]]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node], data: str, *, default: _U | None = None, keys: Literal[False] = False
) -> MultiEdgeDataView[_Node, tuple[_Node, _Node, _U]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node] = None, *, data: str, default: _U | None = None, keys: Literal[True]
) -> MultiEdgeDataView[_Node, tuple[_Node, _Node, Incomplete, _U]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node] = None, *, data: str, default: _U | None = None, keys: Literal[False] = False
) -> MultiEdgeDataView[_Node, tuple[_Node, _Node, _U]]: ...
@overload # type: ignore[override]
def data(self, data: Literal[False], default: Unused = None, nbunch: None = None, *, keys: Literal[True]) -> Self: ...
@overload
def data(
self, data: Literal[False], default: None = None, nbunch: _NBunch[_Node] = None, keys: Literal[False] = False
) -> MultiEdgeDataView[_Node, tuple[_Node, _Node]]: ...
@overload
def data(
self, data: Literal[True] = True, default: None = None, nbunch: _NBunch[_Node] = None, keys: Literal[False] = False
) -> MultiEdgeDataView[_Node, tuple[_Node, _Node, dict[str, Incomplete]]]: ...
@overload
def data(
self, data: Literal[True] = True, default: None = None, nbunch: _NBunch[_Node] = None, *, keys: Literal[True]
) -> MultiEdgeDataView[_Node, tuple[_Node, _Node, Incomplete, dict[str, Incomplete]]]: ...
@overload
def data(
self, data: str, default: _U | None = None, nbunch: _NBunch[_Node] = None, keys: Literal[False] = False
) -> MultiEdgeDataView[_Node, tuple[_Node, _Node, _U]]: ...
@overload
def data(
self, data: str, default: _U | None = None, nbunch: _NBunch[_Node] = None, *, keys: Literal[True]
) -> MultiEdgeDataView[_Node, tuple[_Node, _Node, Incomplete, _U]]: ...

class InMultiEdgeView(OutMultiEdgeView[_Node]):
dataview = InMultiEdgeDataView # type: ignore[assignment]
# Have to override parent's overloads with the proper return type based on dataview
@overload # type: ignore[override]
def __call__( # type: ignore[overload-overlap]
self, nbunch: None = None, data: Literal[False] = False, *, default: Unused = None, keys: Literal[True]
) -> Self: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node] = None, data: Literal[False] = False, *, default: None = None, keys: Literal[False] = False
) -> InMultiEdgeDataView[_Node, tuple[_Node, _Node]]: ...
@overload
def __call__(
self, nbunch: _Node | Iterable[_Node], data: Literal[False] = False, *, default: None = None, keys: Literal[True]
) -> InMultiEdgeDataView[_Node, tuple[_Node, _Node, Incomplete]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node] = None, *, data: Literal[True], default: None = None, keys: Literal[True]
) -> InMultiEdgeDataView[_Node, tuple[_Node, _Node, Incomplete, dict[str, Incomplete]]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node], data: Literal[True], *, default: None = None, keys: Literal[True]
) -> InMultiEdgeDataView[_Node, tuple[_Node, _Node, Incomplete, dict[str, Incomplete]]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node] = None, *, data: Literal[True], default: None = None, keys: Literal[False] = False
) -> InMultiEdgeDataView[_Node, tuple[_Node, _Node, dict[str, Incomplete]]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node], data: str, *, default: _U | None = None, keys: Literal[False] = False
) -> InMultiEdgeDataView[_Node, tuple[_Node, _Node, _U]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node] = None, *, data: str, default: _U | None = None, keys: Literal[True]
) -> InMultiEdgeDataView[_Node, tuple[_Node, _Node, Incomplete, _U]]: ...
@overload
def __call__(
self, nbunch: _NBunch[_Node] = None, *, data: str, default: _U | None = None, keys: Literal[False] = False
) -> InMultiEdgeDataView[_Node, tuple[_Node, _Node, _U]]: ...
@overload # type: ignore[override]
def data(self, data: Literal[False], default: Unused = None, nbunch: None = None, *, keys: Literal[True]) -> Self: ...
@overload
def data(
self, data: Literal[False], default: None = None, nbunch: _NBunch[_Node] = None, keys: Literal[False] = False
) -> InMultiEdgeDataView[_Node, tuple[_Node, _Node]]: ...
@overload
def data(
self, data: Literal[True] = True, default: None = None, nbunch: _NBunch[_Node] = None, keys: Literal[False] = False
) -> InMultiEdgeDataView[_Node, tuple[_Node, _Node, dict[str, Incomplete]]]: ...
@overload
def data(
self, data: Literal[True] = True, default: None = None, nbunch: _NBunch[_Node] = None, *, keys: Literal[True]
) -> InMultiEdgeDataView[_Node, tuple[_Node, _Node, Incomplete, dict[str, Incomplete]]]: ...
@overload
def data(
self, data: str, default: _U | None = None, nbunch: _NBunch[_Node] = None, keys: Literal[False] = False
) -> InMultiEdgeDataView[_Node, tuple[_Node, _Node, _U]]: ...
@overload
def data(
self, data: str, default: _U | None = None, nbunch: _NBunch[_Node] = None, *, keys: Literal[True]
) -> InMultiEdgeDataView[_Node, tuple[_Node, _Node, Incomplete, _U]]: ...
20 changes: 14 additions & 6 deletions stubs/networkx/networkx/readwrite/text.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,49 @@ from typing import ClassVar

__all__ = ["generate_network_text", "write_network_text"]

class _AsciiBaseGlyphs:
class BaseGlyphs:
@classmethod
def as_dict(cls) -> dict[str, str]: ...

class AsciiBaseGlyphs(BaseGlyphs):
empty: ClassVar[str]
newtree_last: ClassVar[str]
newtree_mid: ClassVar[str]
endof_forest: ClassVar[str]
within_forest: ClassVar[str]
within_tree: ClassVar[str]

class AsciiDirectedGlyphs(_AsciiBaseGlyphs):
class AsciiDirectedGlyphs(AsciiBaseGlyphs):
last: ClassVar[str]
mid: ClassVar[str]
backedge: ClassVar[str]
vertical_edge: ClassVar[str]

class AsciiUndirectedGlyphs(_AsciiBaseGlyphs):
class AsciiUndirectedGlyphs(AsciiBaseGlyphs):
last: ClassVar[str]
mid: ClassVar[str]
backedge: ClassVar[str]
vertical_edge: ClassVar[str]

class _UtfBaseGlyphs:
class UtfBaseGlyphs(BaseGlyphs):
empty: ClassVar[str]
newtree_last: ClassVar[str]
newtree_mid: ClassVar[str]
endof_forest: ClassVar[str]
within_forest: ClassVar[str]
within_tree: ClassVar[str]

class UtfDirectedGlyphs(_UtfBaseGlyphs):
class UtfDirectedGlyphs(UtfBaseGlyphs):
last: ClassVar[str]
mid: ClassVar[str]
backedge: ClassVar[str]
vertical_edge: ClassVar[str]

class UtfUndirectedGlyphs(_UtfBaseGlyphs):
class UtfUndirectedGlyphs(UtfBaseGlyphs):
last: ClassVar[str]
mid: ClassVar[str]
backedge: ClassVar[str]
vertical_edge: ClassVar[str]

def generate_network_text(
graph,
Expand Down
Loading