Skip to content

Commit e8ba06f

Browse files
Add @disjoint_base decorator in the stdlib (#14599)
And fix some other new stubtest finds.
1 parent 2565f34 commit e8ba06f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+700
-306
lines changed

.github/workflows/stubtest_stdlib.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,8 @@ jobs:
4646
check-latest: true
4747
- name: Install dependencies
4848
run: pip install -r requirements-tests.txt
49+
# Temporary to get @disjoint_base support; can remove once mypy 1.18 is released
50+
- name: Install mypy from git
51+
run: pip install git+https://github.com/python/mypy.git@116b92bae7b5dbf5e6bd36fd9b0c6804973e5554
4952
- name: Run stubtest
5053
run: python tests/stubtest_stdlib.py

stdlib/@tests/stubtest_allowlists/common.txt

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@
44

55
# Please keep sorted alphabetically
66

7-
collections\.ChainMap\.fromkeys # https://github.com/python/mypy/issues/17023
8-
http.client.HTTPConnection.response_class # the actual type at runtime is abc.ABCMeta
97
importlib.abc.Loader.exec_module # See Lib/importlib/_abc.py. Might be defined for backwards compatibility
108
importlib.abc.MetaPathFinder.find_spec # Not defined on the actual class, but expected to exist.
119
importlib.abc.PathEntryFinder.find_spec # Not defined on the actual class, but expected to exist.
1210
tkinter.simpledialog.[A-Z_]+
1311
tkinter.simpledialog.TclVersion
1412
tkinter.simpledialog.TkVersion
15-
tkinter.Text.count # stubtest somehow thinks that index1 parameter has a default value, but it doesn't in any of the overloads
13+
builtins.tuple # should have @disjoint_base but hits pyright issue
14+
tarfile.TarInfo.__slots__ # it's a big dictionary at runtime and the dictionary values are a bit long
1615

1716

1817
# ===============================================================
@@ -201,7 +200,6 @@ _markupbase.ParserBase.parse_marked_section
201200

202201
_pydecimal.* # See comments in file
203202
_typeshed.* # Utility types for typeshed, doesn't exist at runtime
204-
argparse.ArgumentParser.__init__ # stubtest doesn't recognise the runtime default (a class) as being compatible with a callback protocol (the stub annotation)
205203
argparse.Namespace.__getattr__ # The whole point of this class is its attributes are dynamic
206204

207205
# Runtime AST node runtime constructor behaviour is too loose.
@@ -218,8 +216,6 @@ argparse.Namespace.__setattr__ # should allow setting any attribute
218216

219217
ast.ImportFrom.level # None on the class, but never None on instances
220218
ast.NodeVisitor.visit_\w+ # Methods are discovered dynamically, see #3796
221-
_?asyncio.Future.__init__ # Usually initialized from c object
222-
asyncio.futures.Future.__init__ # Usually initialized from c object
223219

224220
# Condition functions are exported in __init__
225221
asyncio.Condition.acquire
@@ -230,7 +226,6 @@ asyncio.locks.Condition.locked
230226
asyncio.locks.Condition.release
231227

232228
builtins.memoryview.__contains__ # C type that implements __getitem__
233-
builtins.object.__init__ # default C signature is incorrect
234229
builtins.reveal_locals # Builtins that type checkers pretends exist
235230
builtins.reveal_type # Builtins that type checkers pretends exist
236231
builtins.type.__dict__ # read-only but not actually a property; stubtest thinks it's a mutable attribute.
@@ -260,8 +255,6 @@ configparser.SectionProxy.getint # SectionProxy get functions are set in __init
260255
contextlib.AbstractAsyncContextManager.__class_getitem__
261256
contextlib.AbstractContextManager.__class_getitem__
262257

263-
_?contextvars.Context.__init__ # C signature is broader than what is actually accepted
264-
265258
copy.PyStringMap # defined only in Jython
266259

267260
# The Dialect properties are initialized as None in Dialect but their values are enforced in _Dialect
@@ -329,9 +322,6 @@ importlib.machinery.ExtensionFileLoader.get_filename
329322
inspect.Parameter.__init__
330323
inspect.Signature.__init__
331324

332-
inspect.Parameter.empty # set as private marker _empty
333-
inspect.Signature.empty # set as private marker _empty
334-
335325
logging.LogRecord.__setattr__ # doesn't exist, but makes things easy if we pretend it does
336326

337327
# Iterable classes that don't define __iter__ at runtime (usually iterable via __getitem__)
@@ -377,11 +367,6 @@ multiprocessing.queues.JoinableQueue.__init__
377367
multiprocessing.queues.Queue.__init__
378368
multiprocessing.queues.SimpleQueue.__init__
379369

380-
# alias for a class defined elsewhere,
381-
# mypy infers the variable has type `(*args) -> ForkingPickler`
382-
# but stubtest infers the runtime type as <class ForkingPickler>
383-
multiprocessing.reduction.AbstractReducer.ForkingPickler
384-
385370
# These methods are dynamically created after object initialization,
386371
# copied from a wrapped lock object. Stubtest doesn't think they exist
387372
# because of that.
@@ -406,7 +391,6 @@ os.PathLike.__class_getitem__ # PathLike is a protocol; we don't expect all Pat
406391

407392
pickle._Pickler\..* # Best effort typing for undocumented internals
408393
pickle._Unpickler\..* # Best effort typing for undocumented internals
409-
_?queue.SimpleQueue.__init__ # C signature is broader than what is actually accepted
410394
shutil.rmtree # function with attributes, which we approximate with a callable protocol
411395
socketserver.BaseServer.get_request # Not implemented, but expected to exist on subclasses.
412396
ssl.PROTOCOL_SSLv2 # Depends on the existence and flags of SSL

stdlib/@tests/stubtest_allowlists/darwin.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ curses.LINES # Initialized only after initscr call
4343
curses.has_key # stubtest gets confused because this is both a module and a function in curses
4444
multiprocessing.popen_spawn_win32 # exists on Darwin but fails to import
4545
readline.append_history_file # Only available if compiled with GNU readline, not editline
46-
select.kqueue.__init__ # default C signature is wrong
4746
select.poll # Actually a function; we have a class so it can be used as a type
4847

4948
# Some of these exist on non-windows, but they are useless and this is not intended

stdlib/@tests/stubtest_allowlists/py310.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ asyncio.locks.Lock.__init__
5555
asyncio.locks.Semaphore.__init__
5656
asyncio.queues.Queue.__init__
5757

58+
_random.Random.__init__ # Issues with __new__/__init__ correspondence
59+
5860
bdb.Breakpoint.clearBreakpoints # Exists at runtime, but missing from stubs
5961

6062

@@ -100,7 +102,6 @@ typing_extensions.Sentinel.__call__
100102
# <= 3.11
101103
# =======
102104

103-
_?bz2.BZ2Decompressor.__init__ # function does not accept parameters but C signature is set
104105
enum.Enum._generate_next_value_
105106
importlib.abc.Finder.find_module
106107
urllib.request.HTTPPasswordMgrWithPriorAuth.__init__ # Args are passed as is to super, so super args are specified

stdlib/@tests/stubtest_allowlists/py311.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ importlib.metadata._meta.SimplePath.__truediv__ # Runtime definition of protoco
6868
# <= 3.11
6969
# =======
7070

71-
_?bz2.BZ2Decompressor.__init__ # function does not accept parameters but C signature is set
7271
enum.Enum._generate_next_value_
7372
importlib.abc.Finder.find_module
7473
urllib.request.HTTPPasswordMgrWithPriorAuth.__init__ # Args are passed as is to super, so super args are specified

stdlib/@tests/stubtest_allowlists/py39.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ typing_extensions.Sentinel.__call__
5454
# <= 3.11
5555
# =======
5656

57-
_?bz2.BZ2Decompressor.__init__ # function does not accept parameters but C signature is set
5857
enum.Enum._generate_next_value_
5958
importlib.abc.Finder.find_module
6059
urllib.request.HTTPPasswordMgrWithPriorAuth.__init__ # Args are passed as is to super, so super args are specified

stdlib/@tests/stubtest_allowlists/win32.txt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@
22
# TODO: Allowlist entries that should be fixed
33
# ============================================
44

5-
# alias for a class defined elsewhere,
6-
# mypy infers the variable has type `(*args) -> DupHandle` but stubtest infers the runtime type as <class DupHandle>
7-
multiprocessing.reduction.AbstractReducer.DupHandle
8-
95
# Exists at runtime, but missing from stubs
106
_winapi.CreateFileMapping
117
_winapi.MapViewOfFile

stdlib/_asyncio.pyi

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ from collections.abc import Awaitable, Callable, Coroutine, Generator
44
from contextvars import Context
55
from types import FrameType, GenericAlias
66
from typing import Any, Literal, TextIO, TypeVar
7-
from typing_extensions import Self, TypeAlias
7+
from typing_extensions import Self, TypeAlias, disjoint_base
88

99
_T = TypeVar("_T")
1010
_T_co = TypeVar("_T_co", covariant=True)
1111
_TaskYieldType: TypeAlias = Future[object] | None
1212

13+
@disjoint_base
1314
class Future(Awaitable[_T]):
1415
_state: str
1516
@property
@@ -49,6 +50,7 @@ else:
4950
# While this is true in general, here it's sort-of okay to have a covariant subclass,
5051
# since the only reason why `asyncio.Future` is invariant is the `set_result()` method,
5152
# and `asyncio.Task.set_result()` always raises.
53+
@disjoint_base
5254
class Task(Future[_T_co]): # type: ignore[type-var] # pyright: ignore[reportInvalidTypeArguments]
5355
if sys.version_info >= (3, 12):
5456
def __init__(

stdlib/_csv.pyi

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import sys
33
from _typeshed import SupportsWrite
44
from collections.abc import Iterable
55
from typing import Any, Final, Literal, type_check_only
6-
from typing_extensions import Self, TypeAlias
6+
from typing_extensions import Self, TypeAlias, disjoint_base
77

88
__version__: Final[str]
99

@@ -24,6 +24,7 @@ class Error(Exception): ...
2424

2525
_DialectLike: TypeAlias = str | Dialect | csv.Dialect | type[Dialect | csv.Dialect]
2626

27+
@disjoint_base
2728
class Dialect:
2829
delimiter: str
2930
quotechar: str | None
@@ -48,6 +49,7 @@ class Dialect:
4849

4950
if sys.version_info >= (3, 10):
5051
# This class calls itself _csv.reader.
52+
@disjoint_base
5153
class Reader:
5254
@property
5355
def dialect(self) -> Dialect: ...
@@ -56,6 +58,7 @@ if sys.version_info >= (3, 10):
5658
def __next__(self) -> list[str]: ...
5759

5860
# This class calls itself _csv.writer.
61+
@disjoint_base
5962
class Writer:
6063
@property
6164
def dialect(self) -> Dialect: ...

stdlib/_hashlib.pyi

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ from _typeshed import ReadableBuffer
33
from collections.abc import Callable
44
from types import ModuleType
55
from typing import AnyStr, Protocol, final, overload, type_check_only
6-
from typing_extensions import Self, TypeAlias
6+
from typing_extensions import Self, TypeAlias, disjoint_base
77

88
_DigestMod: TypeAlias = str | Callable[[], _HashObject] | ModuleType | None
99

@@ -22,6 +22,7 @@ class _HashObject(Protocol):
2222
def hexdigest(self) -> str: ...
2323
def update(self, obj: ReadableBuffer, /) -> None: ...
2424

25+
@disjoint_base
2526
class HASH:
2627
@property
2728
def digest_size(self) -> int: ...

0 commit comments

Comments
 (0)