Skip to content

Replace validate_stubs scripts with stubtest #371

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
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
dbf819b
Replace validate_stubs scripts with stubtest
Avasam May 23, 2025
986fbe8
Bump minimum CI Python version to 3.10 because of scipy-stubs
Avasam May 23, 2025
ba3ac03
Merge branch 'main' of https://github.com/microsoft/python-type-stubs…
Avasam May 23, 2025
41a66b4
Post-merge and cross-versions checks fix
Avasam May 23, 2025
179d50a
Merge branch 'main' of https://github.com/microsoft/python-type-stubs…
Avasam May 23, 2025
c88641f
Fix typos
Avasam May 23, 2025
c075039
Merge branch 'main' of https://github.com/microsoft/python-type-stubs…
Avasam May 23, 2025
da7a262
Fixed Python 3.13 cross-platform stubtest issues
Avasam May 24, 2025
0b480e8
Fix all differences between Python 3.10 and 3.13 (on Windows)
Avasam May 24, 2025
662db14
Missed an entry
Avasam May 24, 2025
e529bb0
Fix pyright re-export issues
Avasam May 24, 2025
585b85a
Merge branch 'main' of https://github.com/microsoft/python-type-stubs…
Avasam May 24, 2025
1edd30a
Merge branch 'main' of https://github.com/microsoft/python-type-stubs…
Avasam May 28, 2025
72f5e8e
Merge branch 'main' of https://github.com/microsoft/python-type-stubs…
Avasam May 29, 2025
5d980b3
Remove solved allowlist entries post merge
Avasam May 29, 2025
920b14f
joblib already installed as dep
Avasam May 29, 2025
ac1c1da
Run ruff format
Avasam May 29, 2025
7c2c30e
Forgot an unused import
Avasam May 29, 2025
7a5a540
Discard changes to stubs/sklearn/feature_extraction/_dict_vectorizer.pyi
Avasam May 29, 2025
0d2d6b1
Discard changes to stubs/sklearn/ensemble/_hist_gradient_boosting/pre…
Avasam May 29, 2025
9537ef8
Discard changes to stubs/sklearn/ensemble/_hist_gradient_boosting/bin…
Avasam May 29, 2025
6f295f8
Fix macOS run
Avasam May 30, 2025
d2743a5
Merge branch 'Replace-validate_stubs-scripts-with-stubtest' of https:…
Avasam May 30, 2025
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
3 changes: 3 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ jobs:
- name: Run mypy tests
run: python -m mypy . --python-version=${{ matrix.python-version }}

- name: Run stubtest
run: python tests/run_stubtest.py

hygiene:
runs-on: ubuntu-latest
timeout-minutes: 10
Expand Down
21 changes: 14 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,21 @@ tests = [
"mypy ==1.15.*",
"pyright",

# Typed libraries and stubs
# External type stubs and optional dependencies
"PyOpenGL",
"matplotlib >=3.8",
"pandas-stubs",
"pytest",
"scipy-stubs",
"typing_extensions",

# Untyped libraries and partial stubs. Used to prevent "reportMissingImports" and get inferred typing
"joblib",
# The libraries we're stubbing.
# Needed for stubtest and downloads their dependencies to get known import symbols
"networkx",
"PyOpenGL",
"scikit-image",
"scikit-learn",
"sympy",
"traitlets",
"vispy",
]
dev = [{ include-group = "hygiene" }, { include-group = "tests" }]

Expand Down Expand Up @@ -136,7 +137,6 @@ reportSelfClsParameterName = false
reportUnsupportedDunderAll = "error"

[tool.mypy]
python_version = "3.9" # Target oldest supported Python version
strict = true
check_untyped_defs = true # Strict check on all defs
show_column_numbers = true
Expand All @@ -161,6 +161,13 @@ disable_error_code = [
"assignment", # 744 errors in 155 files
]

[[tool.mypy.overrides]]
# follow_untyped_imports = true will cause stubtest to run mypy on the source
# So disable it for partial stubs
Comment on lines +165 to +166
Copy link
Contributor Author

@Avasam Avasam May 29, 2025

Choose a reason for hiding this comment

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

This doesn't feel like optimal behaviour for stubtest. I'll raise an issue upstream.

module = ["sympy.*"]
follow_untyped_imports = false
disable_error_code = ["import-untyped", "misc"]

[[tool.mypy.overrides]]
# These modules are to be removed soon, not worth solving many issues
module = ["matplotlib.*", "networkx.*"]
Expand All @@ -169,7 +176,7 @@ disable_error_code = [
"misc",
]
[[tool.mypy.overrides]]
module = ["sympy.*", "skimage.*", "sklearn.*"]
module = ["skimage.*", "sklearn.*"]
# TODO: Too many untyped decorators still left
# https://github.com/python/mypy/issues/19148
disable_error_code = ["misc"]
15 changes: 12 additions & 3 deletions stubs/matplotlib/_mathtext.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ from .mathtext import MathtextBackend
# tkinter.tix was removed from Python 3.13
# Recent matplotlib versions define HList in this module
if sys.version_info >= (3, 13):
HList: Incomplete
HList = Incomplete
else:
from tkinter.tix import HList

Expand Down Expand Up @@ -150,14 +150,23 @@ class List(Box):

class Hlist(List):
def __init__(
self, elements, w: float = 0, m: Literal["exactly", "additional"] = "additional", do_kern: bool = True
self,
elements,
w: float = 0,
m: Literal["exactly", "additional"] = "additional",
do_kern: bool = True,
) -> None: ...
def kern(self) -> None: ...
def hpack(self, w: float = 0, m: Literal["exactly", "additional"] = "additional") -> None: ...

class Vlist(List):
def __init__(self, elements, h=0, m=...) -> None: ...
def vpack(self, h: float = ..., m: Literal["exactly", "additional"] = "additional", l: float = ...) -> None: ...
def vpack(
self,
h: float = ...,
m: Literal["exactly", "additional"] = "additional",
l: float = ...,
) -> None: ...

class Rule(Box):
def __init__(self, width: float, height: float, depth: float, state) -> None: ...
Expand Down
3 changes: 1 addition & 2 deletions stubs/matplotlib/backends/backend_ps.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ from matplotlib.backend_bases import FigureCanvasBase, FigureManagerBase, Graphi
from matplotlib.font_manager import FontProperties
from matplotlib.text import Text
from matplotlib.transforms import Affine2DBase, Transform
from traitlets import Int

from . import _backend_pdf_ps

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

class FigureCanvasPS(FigureCanvasBase):
fixed_dpi: Int = ...
fixed_dpi: int = ...
filetypes: dict[str, str] = ...
def get_default_filetype(self) -> str: ...
def print_ps(self, outfile, *args, metadata=None, papertype=None, orientation="portrait", **kwargs) -> None: ...
Expand Down
52 changes: 4 additions & 48 deletions stubs/networkx/generators/atlas.pyi
Original file line number Diff line number Diff line change
@@ -1,56 +1,12 @@
import gzip
import os
import os.path
from itertools import islice
from importlib.abc import Traversable
from typing import Final

from numpy.typing import ArrayLike

from ..classes.graph import Graph

__all__ = ["graph_atlas", "graph_atlas_g"]

#: The total number of graphs in the atlas.
#:
#: The graphs are labeled starting from 0 and extending to (but not
#: including) this number.
NUM_GRAPHS: int = ...

#: The absolute path representing the directory containing this file.
THIS_DIR = ...

#: The path to the data file containing the graph edge lists.
#:
#: This is the absolute path of the gzipped text file containing the
#: edge list for each graph in the atlas. The file contains one entry
#: per graph in the atlas, in sequential order, starting from graph
#: number 0 and extending through graph number 1252 (see
#: :data:`NUM_GRAPHS`). Each entry looks like
#:
#: .. sourcecode:: text
#:
#: GRAPH 6
#: NODES 3
#: 0 1
#: 0 2
#:
#: where the first two lines are the graph's index in the atlas and the
#: number of nodes in the graph, and the remaining lines are the edge
#: list.
#:
#: This file was generated from a Python list of graphs via code like
#: the following::
#:
#: import gzip
#: from networkx.generators.atlas import graph_atlas_g
#: from networkx.readwrite.edgelist import write_edgelist
#:
#: with gzip.open('atlas.dat.gz', 'wb') as f:
#: for i, G in enumerate(graph_atlas_g()):
#: f.write(bytes(f'GRAPH {i}\n', encoding='utf-8'))
#: f.write(bytes(f'NODES {len(G:Graph)}\n', encoding='utf-8'))
#: write_edgelist(G:Graph, f, data=False)
#:
ATLAS_FILE = ...
NUM_GRAPHS: Final = 1253
ATLAS_FILE: Traversable

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