Skip to content

Commit b311fd7

Browse files
authored
Replace validate_stubs scripts with stubtest (#371)
1 parent ba1968b commit b311fd7

File tree

35 files changed

+8695
-672
lines changed

35 files changed

+8695
-672
lines changed

.github/workflows/test.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ jobs:
4444
- name: Run mypy tests
4545
run: python -m mypy . --python-version=${{ matrix.python-version }}
4646

47+
- name: Run stubtest
48+
run: python tests/run_stubtest.py
49+
4750
hygiene:
4851
runs-on: ubuntu-latest
4952
timeout-minutes: 10

pyproject.toml

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,21 @@ tests = [
1414
"mypy ==1.15.*",
1515
"pyright",
1616

17-
# Typed libraries and stubs
17+
# External type stubs and optional dependencies
18+
"PyOpenGL",
1819
"matplotlib >=3.8",
1920
"pandas-stubs",
2021
"pytest",
2122
"scipy-stubs",
2223
"typing_extensions",
2324

24-
# Untyped libraries and partial stubs. Used to prevent "reportMissingImports" and get inferred typing
25-
"joblib",
25+
# The libraries we're stubbing.
26+
# Needed for stubtest and downloads their dependencies to get known import symbols
2627
"networkx",
27-
"PyOpenGL",
28+
"scikit-image",
2829
"scikit-learn",
2930
"sympy",
30-
"traitlets",
31+
"vispy",
3132
]
3233
dev = [{ include-group = "hygiene" }, { include-group = "tests" }]
3334

@@ -136,7 +137,6 @@ reportSelfClsParameterName = false
136137
reportUnsupportedDunderAll = "error"
137138

138139
[tool.mypy]
139-
python_version = "3.9" # Target oldest supported Python version
140140
strict = true
141141
check_untyped_defs = true # Strict check on all defs
142142
show_column_numbers = true
@@ -161,6 +161,13 @@ disable_error_code = [
161161
"assignment", # 744 errors in 155 files
162162
]
163163

164+
[[tool.mypy.overrides]]
165+
# follow_untyped_imports = true will cause stubtest to run mypy on the source
166+
# So disable it for partial stubs
167+
module = ["sympy.*"]
168+
follow_untyped_imports = false
169+
disable_error_code = ["import-untyped", "misc"]
170+
164171
[[tool.mypy.overrides]]
165172
# These modules are to be removed soon, not worth solving many issues
166173
module = ["matplotlib.*", "networkx.*"]
@@ -169,7 +176,7 @@ disable_error_code = [
169176
"misc",
170177
]
171178
[[tool.mypy.overrides]]
172-
module = ["sympy.*", "skimage.*", "sklearn.*"]
179+
module = ["skimage.*", "sklearn.*"]
173180
# TODO: Too many untyped decorators still left
174181
# https://github.com/python/mypy/issues/19148
175182
disable_error_code = ["misc"]

stubs/matplotlib/_mathtext.pyi

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ from .mathtext import MathtextBackend
1010
# tkinter.tix was removed from Python 3.13
1111
# Recent matplotlib versions define HList in this module
1212
if sys.version_info >= (3, 13):
13-
HList: Incomplete
13+
HList = Incomplete
1414
else:
1515
from tkinter.tix import HList
1616

@@ -150,14 +150,23 @@ class List(Box):
150150

151151
class Hlist(List):
152152
def __init__(
153-
self, elements, w: float = 0, m: Literal["exactly", "additional"] = "additional", do_kern: bool = True
153+
self,
154+
elements,
155+
w: float = 0,
156+
m: Literal["exactly", "additional"] = "additional",
157+
do_kern: bool = True,
154158
) -> None: ...
155159
def kern(self) -> None: ...
156160
def hpack(self, w: float = 0, m: Literal["exactly", "additional"] = "additional") -> None: ...
157161

158162
class Vlist(List):
159163
def __init__(self, elements, h=0, m=...) -> None: ...
160-
def vpack(self, h: float = ..., m: Literal["exactly", "additional"] = "additional", l: float = ...) -> None: ...
164+
def vpack(
165+
self,
166+
h: float = ...,
167+
m: Literal["exactly", "additional"] = "additional",
168+
l: float = ...,
169+
) -> None: ...
161170

162171
class Rule(Box):
163172
def __init__(self, width: float, height: float, depth: float, state) -> None: ...

stubs/matplotlib/backends/backend_ps.pyi

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ from matplotlib.backend_bases import FigureCanvasBase, FigureManagerBase, Graphi
55
from matplotlib.font_manager import FontProperties
66
from matplotlib.text import Text
77
from matplotlib.transforms import Affine2DBase, Transform
8-
from traitlets import Int
98

109
from . import _backend_pdf_ps
1110

@@ -84,7 +83,7 @@ class _Orientation(Enum):
8483
def swap_if_landscape(self, shape: tuple[float, int]) -> tuple[float, int]: ...
8584

8685
class FigureCanvasPS(FigureCanvasBase):
87-
fixed_dpi: Int = ...
86+
fixed_dpi: int = ...
8887
filetypes: dict[str, str] = ...
8988
def get_default_filetype(self) -> str: ...
9089
def print_ps(self, outfile, *args, metadata=None, papertype=None, orientation="portrait", **kwargs) -> None: ...
Lines changed: 4 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,12 @@
1-
import gzip
2-
import os
3-
import os.path
4-
from itertools import islice
1+
from importlib.abc import Traversable
2+
from typing import Final
53

64
from numpy.typing import ArrayLike
75

8-
from ..classes.graph import Graph
9-
106
__all__ = ["graph_atlas", "graph_atlas_g"]
117

12-
#: The total number of graphs in the atlas.
13-
#:
14-
#: The graphs are labeled starting from 0 and extending to (but not
15-
#: including) this number.
16-
NUM_GRAPHS: int = ...
17-
18-
#: The absolute path representing the directory containing this file.
19-
THIS_DIR = ...
20-
21-
#: The path to the data file containing the graph edge lists.
22-
#:
23-
#: This is the absolute path of the gzipped text file containing the
24-
#: edge list for each graph in the atlas. The file contains one entry
25-
#: per graph in the atlas, in sequential order, starting from graph
26-
#: number 0 and extending through graph number 1252 (see
27-
#: :data:`NUM_GRAPHS`). Each entry looks like
28-
#:
29-
#: .. sourcecode:: text
30-
#:
31-
#: GRAPH 6
32-
#: NODES 3
33-
#: 0 1
34-
#: 0 2
35-
#:
36-
#: where the first two lines are the graph's index in the atlas and the
37-
#: number of nodes in the graph, and the remaining lines are the edge
38-
#: list.
39-
#:
40-
#: This file was generated from a Python list of graphs via code like
41-
#: the following::
42-
#:
43-
#: import gzip
44-
#: from networkx.generators.atlas import graph_atlas_g
45-
#: from networkx.readwrite.edgelist import write_edgelist
46-
#:
47-
#: with gzip.open('atlas.dat.gz', 'wb') as f:
48-
#: for i, G in enumerate(graph_atlas_g()):
49-
#: f.write(bytes(f'GRAPH {i}\n', encoding='utf-8'))
50-
#: f.write(bytes(f'NODES {len(G:Graph)}\n', encoding='utf-8'))
51-
#: write_edgelist(G:Graph, f, data=False)
52-
#:
53-
ATLAS_FILE = ...
8+
NUM_GRAPHS: Final = 1253
9+
ATLAS_FILE: Traversable
5410

5511
def graph_atlas(i: int) -> ArrayLike: ...
5612
def graph_atlas_g() -> ArrayLike: ...

0 commit comments

Comments
 (0)