Skip to content

Commit 10c9d8c

Browse files
authored
Add @final to many unsubclassable stdlib classes (#6299)
1 parent 5b94c6a commit 10c9d8c

17 files changed

+48
-9
lines changed

stdlib/_thread.pyi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ import sys
22
from threading import Thread
33
from types import TracebackType
44
from typing import Any, Callable, NoReturn, Optional, Tuple, Type
5+
from typing_extensions import final
56

67
error = RuntimeError
78

89
def _count() -> int: ...
910

1011
_dangling: Any
1112

13+
@final
1214
class LockType:
1315
def acquire(self, blocking: bool = ..., timeout: float = ...) -> bool: ...
1416
def release(self) -> None: ...
@@ -29,6 +31,7 @@ TIMEOUT_MAX: float
2931

3032
if sys.version_info >= (3, 8):
3133
def get_native_id() -> int: ... # only available on some platforms
34+
@final
3235
class _ExceptHookArgs(Tuple[Type[BaseException], Optional[BaseException], Optional[TracebackType], Optional[Thread]]):
3336
@property
3437
def exc_type(self) -> Type[BaseException]: ...

stdlib/_tkinter.pyi

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from typing import Any
2-
from typing_extensions import Literal
2+
from typing_extensions import Literal, final
33

44
# _tkinter is meant to be only used internally by tkinter, but some tkinter
55
# functions e.g. return _tkinter.Tcl_Obj objects. Tcl_Obj represents a Tcl
@@ -14,6 +14,7 @@ from typing_extensions import Literal
1414
# >>> text.tag_add('foo', '1.0', 'end')
1515
# >>> text.tag_ranges('foo')
1616
# (<textindex object: '1.0'>, <textindex object: '2.0'>)
17+
@final
1718
class Tcl_Obj:
1819
string: str # str(tclobj) returns this
1920
typename: str
@@ -37,6 +38,7 @@ class TclError(Exception): ...
3738
#
3839
# eval always returns str because _tkinter_tkapp_eval_impl in _tkinter.c calls
3940
# Tkapp_UnicodeResult, and it returns a string when it succeeds.
41+
@final
4042
class TkappType:
4143
# Please keep in sync with tkinter.Tk
4244
def call(self, __command: Any, *args: Any) -> Any: ...

stdlib/_weakref.pyi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import sys
22
from typing import Any, Callable, Generic, TypeVar, overload
3+
from typing_extensions import final
34

45
if sys.version_info >= (3, 9):
56
from types import GenericAlias
67

78
_C = TypeVar("_C", bound=Callable[..., Any])
89
_T = TypeVar("_T")
910

11+
@final
1012
class CallableProxyType(Generic[_C]): # "weakcallableproxy"
1113
def __getattr__(self, attr: str) -> Any: ...
1214

15+
@final
1316
class ProxyType(Generic[_T]): # "weakproxy"
1417
def __getattr__(self, attr: str) -> Any: ...
1518

stdlib/_winapi.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import sys
22
from typing import Any, NoReturn, Sequence, overload
3-
from typing_extensions import Literal
3+
from typing_extensions import Literal, final
44

55
CREATE_NEW_CONSOLE: int
66
CREATE_NEW_PROCESS_GROUP: int
@@ -126,7 +126,7 @@ def WriteFile(handle: int, buffer: bytes, overlapped: Literal[True]) -> tuple[Ov
126126
def WriteFile(handle: int, buffer: bytes, overlapped: Literal[False] = ...) -> tuple[int, int]: ...
127127
@overload
128128
def WriteFile(handle: int, buffer: bytes, overlapped: int | bool) -> tuple[Any, int]: ...
129-
129+
@final
130130
class Overlapped:
131131
event: int
132132
def GetOverlappedResult(self, __wait: bool) -> tuple[int, int]: ...

stdlib/bz2.pyi

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import sys
33
from _compression import BaseStream
44
from _typeshed import ReadableBuffer, Self, StrOrBytesPath, WriteableBuffer
55
from typing import IO, Any, Iterable, Protocol, TextIO, TypeVar, overload
6-
from typing_extensions import Literal, SupportsIndex
6+
from typing_extensions import Literal, SupportsIndex, final
77

88
# The following attributes and methods are optional:
99
# def fileno(self) -> int: ...
@@ -118,11 +118,13 @@ class BZ2File(BaseStream, IO[bytes]):
118118
def write(self, data: ReadableBuffer) -> int: ...
119119
def writelines(self, seq: Iterable[ReadableBuffer]) -> None: ...
120120

121+
@final
121122
class BZ2Compressor(object):
122123
def __init__(self, compresslevel: int = ...) -> None: ...
123124
def compress(self, __data: bytes) -> bytes: ...
124125
def flush(self) -> bytes: ...
125126

127+
@final
126128
class BZ2Decompressor(object):
127129
def decompress(self, data: bytes, max_length: int = ...) -> bytes: ...
128130
@property

stdlib/collections/__init__.pyi

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import sys
22
from _typeshed import Self
33
from builtins import _dict_items, _dict_keys, _dict_values
44
from typing import Any, Dict, Generic, NoReturn, Tuple, Type, TypeVar, overload
5+
from typing_extensions import final
56

67
if sys.version_info >= (3, 10):
78
from typing import Callable, Iterable, Iterator, Mapping, MutableMapping, MutableSequence, Reversible, Sequence
@@ -240,12 +241,15 @@ class Counter(Dict[_T, int], Generic[_T]):
240241
def __iand__(self, other: Counter[_T]) -> Counter[_T]: ...
241242
def __ior__(self, other: Counter[_T]) -> Counter[_T]: ... # type: ignore
242243

244+
@final
243245
class _OrderedDictKeysView(_dict_keys[_KT_co, _VT_co], Reversible[_KT_co]):
244246
def __reversed__(self) -> Iterator[_KT_co]: ...
245247

248+
@final
246249
class _OrderedDictItemsView(_dict_items[_KT_co, _VT_co], Reversible[Tuple[_KT_co, _VT_co]]):
247250
def __reversed__(self) -> Iterator[tuple[_KT_co, _VT_co]]: ...
248251

252+
@final
249253
class _OrderedDictValuesView(_dict_values[_KT_co, _VT_co], Reversible[_VT_co], Generic[_KT_co, _VT_co]):
250254
def __reversed__(self) -> Iterator[_VT_co]: ...
251255

stdlib/datetime.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import sys
22
from time import struct_time
33
from typing import ClassVar, NamedTuple, SupportsAbs, Type, TypeVar, overload
4+
from typing_extensions import final
45

56
_S = TypeVar("_S")
67

@@ -16,6 +17,7 @@ class tzinfo:
1617
# Alias required to avoid name conflicts with date(time).tzinfo.
1718
_tzinfo = tzinfo
1819

20+
@final
1921
class timezone(tzinfo):
2022
utc: ClassVar[timezone]
2123
min: ClassVar[timezone]

stdlib/functools.pyi

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import sys
22
import types
33
from _typeshed import SupportsItems, SupportsLessThan
44
from typing import Any, Callable, Generic, Hashable, Iterable, NamedTuple, Sequence, Set, Sized, Tuple, Type, TypeVar, overload
5-
from typing_extensions import ParamSpec
5+
from typing_extensions import ParamSpec, final
66

77
if sys.version_info >= (3, 9):
88
from types import GenericAlias
@@ -24,6 +24,7 @@ class _CacheInfo(NamedTuple):
2424
maxsize: int
2525
currsize: int
2626

27+
@final
2728
class _lru_cache_wrapper(Generic[_P, _T]): # type: ignore
2829
__wrapped__: Callable[_P, _T] # type: ignore
2930
def __call__(self, *args: _P.args, **kwargs: _P.kwargs) -> _T: ... # type: ignore

stdlib/lzma.pyi

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import io
22
from _typeshed import ReadableBuffer, Self, StrOrBytesPath
33
from typing import IO, Any, Mapping, Sequence, TextIO, Union, overload
4-
from typing_extensions import Literal
4+
from typing_extensions import Literal, final
55

66
_OpenBinaryWritingMode = Literal["w", "wb", "x", "xb", "a", "ab"]
77
_OpenTextWritingMode = Literal["wt", "xt", "at"]
@@ -40,6 +40,7 @@ PRESET_DEFAULT: int
4040
PRESET_EXTREME: int
4141

4242
# from _lzma.c
43+
@final
4344
class LZMADecompressor(object):
4445
def __init__(self, format: int | None = ..., memlimit: int | None = ..., filters: _FilterChain | None = ...) -> None: ...
4546
def decompress(self, data: bytes, max_length: int = ...) -> bytes: ...
@@ -53,6 +54,7 @@ class LZMADecompressor(object):
5354
def needs_input(self) -> bool: ...
5455

5556
# from _lzma.c
57+
@final
5658
class LZMACompressor(object):
5759
def __init__(
5860
self, format: int | None = ..., check: int = ..., preset: int | None = ..., filters: _FilterChain | None = ...

stdlib/operator.pyi

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ from typing import (
1111
TypeVar,
1212
overload,
1313
)
14+
from typing_extensions import final
1415

1516
_T = TypeVar("_T")
1617
_T_co = TypeVar("_T_co", covariant=True)
@@ -115,7 +116,7 @@ def __setitem__(a: MutableSequence[_T], b: slice, c: Sequence[_T]) -> None: ...
115116
@overload
116117
def __setitem__(a: MutableMapping[_K, _V], b: _K, c: _V) -> None: ...
117118
def length_hint(__obj: Any, __default: int = ...) -> int: ...
118-
119+
@final
119120
class attrgetter(Generic[_T_co]):
120121
@overload
121122
def __new__(cls, attr: str) -> attrgetter[Any]: ...
@@ -129,6 +130,7 @@ class attrgetter(Generic[_T_co]):
129130
def __new__(cls, attr: str, *attrs: str) -> attrgetter[Tuple[Any, ...]]: ...
130131
def __call__(self, obj: Any) -> _T_co: ...
131132

133+
@final
132134
class itemgetter(Generic[_T_co]):
133135
@overload
134136
def __new__(cls, item: Any) -> itemgetter[Any]: ...
@@ -142,6 +144,7 @@ class itemgetter(Generic[_T_co]):
142144
def __new__(cls, item: Any, *items: Any) -> itemgetter[Tuple[Any, ...]]: ...
143145
def __call__(self, obj: Any) -> _T_co: ...
144146

147+
@final
145148
class methodcaller:
146149
def __init__(self, __name: str, *args: Any, **kwargs: Any) -> None: ...
147150
def __call__(self, obj: Any) -> Any: ...

stdlib/os/__init__.pyi

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ from typing import (
3737
overload,
3838
runtime_checkable,
3939
)
40-
from typing_extensions import Literal
40+
from typing_extensions import Literal, final
4141

4242
from . import path as _path
4343

@@ -262,6 +262,7 @@ if sys.platform != "win32":
262262
TMP_MAX: int # Undocumented, but used by tempfile
263263

264264
# ----- os classes (structures) -----
265+
@final
265266
class stat_result:
266267
# For backward compatibility, the return value of stat() is also
267268
# accessible as a tuple of at least 10 integers giving the most important
@@ -314,6 +315,7 @@ class PathLike(Protocol[_AnyStr_co]):
314315

315316
_FdOrAnyPath = Union[int, StrOrBytesPath]
316317

318+
@final
317319
class DirEntry(Generic[AnyStr]):
318320
# This is what the scandir iterator yields
319321
# The constructor is hidden
@@ -334,6 +336,7 @@ if sys.platform != "win32":
334336
_Tuple11Int = Tuple[int, int, int, int, int, int, int, int, int, int, int]
335337
if sys.version_info >= (3, 7):
336338
# f_fsid was added in https://github.com/python/cpython/pull/4571
339+
@final
337340
class statvfs_result(_Tuple10Int): # Unix only
338341
def __new__(cls, seq: _Tuple10Int | _Tuple11Int, dict: dict[str, int] = ...) -> statvfs_result: ...
339342
n_fields: int
@@ -566,6 +569,7 @@ if sys.platform != "win32":
566569
def readv(__fd: int, __buffers: Sequence[bytearray]) -> int: ...
567570
def writev(__fd: int, __buffers: Sequence[bytes]) -> int: ...
568571

572+
@final
569573
class terminal_size(Tuple[int, int]):
570574
columns: int
571575
lines: int

stdlib/pickle.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import sys
22
from typing import Any, Callable, ClassVar, Iterable, Iterator, Mapping, Optional, Protocol, Tuple, Type, Union
3+
from typing_extensions import final
34

45
HIGHEST_PROTOCOL: int
56
DEFAULT_PROTOCOL: int
@@ -15,6 +16,7 @@ class _WritableFileobj(Protocol):
1516

1617
if sys.version_info >= (3, 8):
1718
# TODO: holistic design for buffer interface (typing.Buffer?)
19+
@final
1820
class PickleBuffer:
1921
# buffer must be a buffer-providing object
2022
def __init__(self, buffer: Any) -> None: ...

stdlib/posix.pyi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@ import sys
22
from _typeshed import StrOrBytesPath
33
from os import PathLike, _ExecEnv, _ExecVArgs, stat_result as stat_result
44
from typing import Any, Iterable, NamedTuple, Sequence, Tuple, overload
5+
from typing_extensions import final
56

7+
@final
68
class uname_result(NamedTuple):
79
sysname: str
810
nodename: str
911
release: str
1012
version: str
1113
machine: str
1214

15+
@final
1316
class times_result(NamedTuple):
1417
user: float
1518
system: float

stdlib/pyexpat/__init__.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import pyexpat.errors as errors
22
import pyexpat.model as model
33
from _typeshed import SupportsRead
44
from typing import Any, Callable, Optional, Tuple
5+
from typing_extensions import final
56

67
EXPAT_VERSION: str # undocumented
78
version_info: tuple[int, int, int] # undocumented
@@ -21,6 +22,7 @@ XML_PARAM_ENTITY_PARSING_ALWAYS: int
2122

2223
_Model = Tuple[int, int, Optional[str], Tuple[Any, ...]]
2324

25+
@final
2426
class XMLParserType(object):
2527
def Parse(self, __data: str | bytes, __isfinal: bool = ...) -> int: ...
2628
def ParseFile(self, __file: SupportsRead[bytes]) -> int: ...

stdlib/time.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import sys
22
from types import SimpleNamespace
33
from typing import Any, NamedTuple, Tuple
4+
from typing_extensions import final
45

56
_TimeTuple = Tuple[int, int, int, int, int, int, int, int, int]
67

@@ -48,6 +49,7 @@ class _struct_time(NamedTuple):
4849
@property
4950
def n_unnamed_fields(self) -> int: ...
5051

52+
@final
5153
class struct_time(_struct_time):
5254
def __init__(
5355
self,

stdlib/typing.pyi

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import collections # Needed by aliases like DefaultDict, see mypy issue 2986
22
import sys
33
from abc import ABCMeta, abstractmethod
44
from types import BuiltinFunctionType, CodeType, FrameType, FunctionType, MethodType, ModuleType, TracebackType
5-
from typing_extensions import Literal as _Literal, ParamSpec as _ParamSpec
5+
from typing_extensions import Literal as _Literal, ParamSpec as _ParamSpec, final as _final
66

77
if sys.version_info >= (3, 7):
88
from types import MethodDescriptorType, MethodWrapperType, WrapperDescriptorType
@@ -545,6 +545,7 @@ class TextIO(IO[str]):
545545

546546
class ByteString(Sequence[int], metaclass=ABCMeta): ...
547547

548+
@_final
548549
class Match(Generic[AnyStr]):
549550
pos: int
550551
endpos: int
@@ -588,6 +589,7 @@ class Match(Generic[AnyStr]):
588589
if sys.version_info >= (3, 9):
589590
def __class_getitem__(cls, item: Any) -> GenericAlias: ...
590591

592+
@_final
591593
class Pattern(Generic[AnyStr]):
592594
flags: int
593595
groupindex: Mapping[str, int]

stdlib/winreg.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from _typeshed import Self
22
from types import TracebackType
33
from typing import Any, Type, Union
4+
from typing_extensions import final
45

56
_KeyType = Union[HKEYType, int]
67

@@ -88,6 +89,7 @@ REG_WHOLE_HIVE_VOLATILE: int # undocumented
8889
error = OSError
8990

9091
# Though this class has a __name__ of PyHKEY, it's exposed as HKEYType for some reason
92+
@final
9193
class HKEYType:
9294
def __bool__(self) -> bool: ...
9395
def __int__(self) -> int: ...

0 commit comments

Comments
 (0)