Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
c28a77a
Update stdlib stubs for Python 3.15
JelleZijlstra May 7, 2026
d38cf68
Fix Python 3.15 stubtest coverage
JelleZijlstra May 7, 2026
de50b34
Expand Python 3.15 stdlib coverage
JelleZijlstra May 7, 2026
938b345
Fix Python 3.15 stub review issues
JelleZijlstra May 7, 2026
7d58087
fixes
JelleZijlstra May 8, 2026
00892f3
more fixes
JelleZijlstra May 8, 2026
39788e6
fix more
JelleZijlstra May 8, 2026
cec3aca
not you
JelleZijlstra May 8, 2026
3a20644
no stubtest for now
JelleZijlstra May 8, 2026
16fbcb9
no commit
JelleZijlstra May 8, 2026
12371f1
Merge remote-tracking branch 'upstream/main' into python315
JelleZijlstra May 8, 2026
0db9084
stubtest
JelleZijlstra May 8, 2026
44d2e56
Add Python 3.15 test infrastructure
JelleZijlstra May 8, 2026
b594b7e
Merge branch 'codex/python315-testing' into python315
JelleZijlstra May 8, 2026
8fdc247
Fix Python 3.15 stubtest guards
JelleZijlstra May 8, 2026
1140f0b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 8, 2026
f5589f6
Fix older stdlib stubtest after 3.15 updates
JelleZijlstra May 8, 2026
7720c6a
Merge remote-tracking branch 'origin/python315' into python315
JelleZijlstra May 8, 2026
4e7b6d7
Allow platform-dependent hashlib exports
JelleZijlstra May 8, 2026
a278ef4
Fix platform 3.15 stubtest allowlists
JelleZijlstra May 8, 2026
ac88edb
Make 3.15 allowlist entries optional
JelleZijlstra May 8, 2026
3c10c06
Relax shared 3.15 allowlist entries
JelleZijlstra May 8, 2026
09ce903
Merge upstream main into python315
JelleZijlstra May 8, 2026
c3d6741
Merge remote-tracking branch 'upstream/main' into python315
JelleZijlstra May 9, 2026
689f19b
Fix Python 3.15 CI after merge
JelleZijlstra May 9, 2026
d8dda00
Complete profiling collector methods
JelleZijlstra May 9, 2026
49c1fd6
Remove covered profiling allowlist entries
JelleZijlstra May 9, 2026
f4770a2
Fix base profiling export parameter
JelleZijlstra May 9, 2026
6ec21e1
Allowlist profiling sampling internals
JelleZijlstra May 9, 2026
10bb878
Fix remaining Python 3.15 stubtest failures
JelleZijlstra May 9, 2026
cc2f7d5
Merge upstream/main into python315
JelleZijlstra May 11, 2026
ba00d28
Organize Python 3.15 stubtest allowlists
JelleZijlstra May 11, 2026
6df830a
Guard NODEV on Python 3.15
JelleZijlstra May 11, 2026
e5d6c98
Merge remote-tracking branch 'upstream/main' into python315
JelleZijlstra May 11, 2026
3bd8325
Tighten Python 3.15 allowlist entries
JelleZijlstra May 13, 2026
e3a4134
Guard ctypes complex type codes
JelleZijlstra May 13, 2026
4e42234
Merge branch 'main' into python315
JelleZijlstra May 13, 2026
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
11 changes: 8 additions & 3 deletions stdlib/VERSIONS
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ mailbox: 3.0-
mailcap: 3.0-3.12
marshal: 3.0-
math: 3.0-
math.integer: 3.15-
mimetypes: 3.0-
mmap: 3.0-
modulefinder: 3.0-
Expand Down Expand Up @@ -242,6 +243,9 @@ posix: 3.0-
posixpath: 3.0-
pprint: 3.0-
profile: 3.0-
profiling: 3.15-
profiling.sampling: 3.15-
profiling.tracing: 3.15-
pstats: 3.0-
pty: 3.0-
pwd: 3.0-
Expand Down Expand Up @@ -276,9 +280,9 @@ socket: 3.0-
socketserver: 3.0-
spwd: 3.0-3.12
sqlite3: 3.0-
sre_compile: 3.0-
sre_constants: 3.0-
sre_parse: 3.0-
sre_compile: 3.0-3.14
sre_constants: 3.0-3.14
sre_parse: 3.0-3.14
ssl: 3.0-
stat: 3.0-
statistics: 3.4-
Expand Down Expand Up @@ -335,6 +339,7 @@ wsgiref: 3.0-
wsgiref.types: 3.11-
xdrlib: 3.0-3.12
xml: 3.0-
xml.utils: 3.15-
xmlrpc: 3.0-
xxlimited: 3.2-
zipapp: 3.5-
Expand Down
6 changes: 4 additions & 2 deletions stdlib/_collections_abc.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ from typing import ( # noqa: Y022,Y038,UP035,Y057,RUF100
AsyncIterable as AsyncIterable,
AsyncIterator as AsyncIterator,
Awaitable as Awaitable,
ByteString as ByteString,
Callable as Callable,
ClassVar,
Collection as Collection,
Expand Down Expand Up @@ -60,8 +59,11 @@ __all__ = [
"ValuesView",
"Sequence",
"MutableSequence",
"ByteString",
]
if sys.version_info < (3, 15):
from typing import ByteString as ByteString # noqa: Y022,Y038,UP035,Y057,RUF100

__all__ += ["ByteString"]
if sys.version_info >= (3, 12):
__all__ += ["Buffer"]

Expand Down
2 changes: 2 additions & 0 deletions stdlib/_decimal.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ _TrapType: TypeAlias = type[DecimalException]

__version__: Final[str]
__libmpdec_version__: Final[str]
if sys.version_info >= (3, 15):
SPEC_VERSION: Final[str]

ROUND_DOWN: Final = "ROUND_DOWN"
ROUND_HALF_UP: Final = "ROUND_HALF_UP"
Expand Down
17 changes: 15 additions & 2 deletions stdlib/_interpqueues.pyi
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import sys
from typing import Any, Literal, SupportsIndex, TypeAlias

_UnboundOp: TypeAlias = Literal[1, 2, 3]
Expand All @@ -6,13 +7,25 @@ class QueueError(RuntimeError): ...
class QueueNotFoundError(QueueError): ...

def bind(qid: SupportsIndex) -> None: ...
def create(maxsize: SupportsIndex, fmt: SupportsIndex, unboundop: _UnboundOp) -> int: ...

if sys.version_info >= (3, 15):
def create(maxsize: SupportsIndex, unboundop: SupportsIndex = -1, fallback: SupportsIndex = -1) -> int: ...

else:
def create(maxsize: SupportsIndex, fmt: SupportsIndex, unboundop: _UnboundOp) -> int: ...

def destroy(qid: SupportsIndex) -> None: ...
def get(qid: SupportsIndex) -> tuple[Any, int, _UnboundOp | None]: ...
def get_count(qid: SupportsIndex) -> int: ...
def get_maxsize(qid: SupportsIndex) -> int: ...
def get_queue_defaults(qid: SupportsIndex) -> tuple[int, _UnboundOp]: ...
def is_full(qid: SupportsIndex) -> bool: ...
def list_all() -> list[tuple[int, int, _UnboundOp]]: ...
def put(qid: SupportsIndex, obj: Any, fmt: SupportsIndex, unboundop: _UnboundOp) -> None: ...

if sys.version_info >= (3, 15):
def put(qid: SupportsIndex, obj: Any, unboundop: SupportsIndex = -1, fallback: SupportsIndex = -1) -> None: ...

else:
def put(qid: SupportsIndex, obj: Any, fmt: SupportsIndex, unboundop: _UnboundOp) -> None: ...

def release(qid: SupportsIndex) -> None: ...
10 changes: 9 additions & 1 deletion stdlib/_json.pyi
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import sys
from collections.abc import Callable
from typing import Any, final
from typing_extensions import Self
Expand Down Expand Up @@ -36,6 +37,8 @@ class make_encoder:

@final
class make_scanner:
if sys.version_info >= (3, 15):
array_hook: Any
object_hook: Any
object_pairs_hook: Any
parse_int: Any
Expand All @@ -48,4 +51,9 @@ class make_scanner:

def encode_basestring(s: str, /) -> str: ...
def encode_basestring_ascii(s: str, /) -> str: ...
def scanstring(string: str, end: int, strict: bool = True) -> tuple[str, int]: ...

if sys.version_info >= (3, 15):
def scanstring(pystr: str, end: int, strict: bool = True, /) -> tuple[str, int]: ...

else:
def scanstring(string: str, end: int, strict: bool = True) -> tuple[str, int]: ...
3 changes: 3 additions & 0 deletions stdlib/_pydecimal.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,6 @@ __all__ = [

if sys.version_info >= (3, 14):
__all__ += ["IEEEContext", "IEEE_CONTEXT_MAX_BITS"]

if sys.version_info >= (3, 15):
__all__ += ["SPEC_VERSION"]
7 changes: 7 additions & 0 deletions stdlib/_socket.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,13 @@ if sys.platform == "linux":
CAN_RAW_JOIN_FILTERS: Final[int]
# Availability: Linux >= 2.6.25
CAN_ISOTP: Final[int]
if sys.version_info >= (3, 15):
SOL_CAN_ISOTP: Final[int]
CAN_ISOTP_OPTS: Final[int]
CAN_ISOTP_RECV_FC: Final[int]
CAN_ISOTP_TX_STMIN: Final[int]
CAN_ISOTP_RX_STMIN: Final[int]
CAN_ISOTP_LL_OPTS: Final[int]
# Availability: Linux >= 5.4
CAN_J1939: Final[int]

Expand Down
2 changes: 2 additions & 0 deletions stdlib/_sqlite3.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ SQLITE_SAVEPOINT: Final = 32
SQLITE_SELECT: Final = 21
SQLITE_TRANSACTION: Final = 22
SQLITE_UPDATE: Final = 23
if sys.version_info >= (3, 15):
SQLITE_KEYWORDS: tuple[str, ...]
adapters: dict[tuple[type[Any], type[Any]], _Adapter[Any]]
converters: dict[str, _Converter]
sqlite_version: str
Expand Down
11 changes: 11 additions & 0 deletions stdlib/_ssl.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ if sys.version_info < (3, 12):
def RAND_status() -> bool: ...
def get_default_verify_paths() -> tuple[str, str, str, str]: ...

if sys.version_info >= (3, 15):
def get_sigalgs() -> list[str]: ...

if sys.platform == "win32":
_EnumRetType: TypeAlias = list[tuple[bytes, str, set[str] | bool]]
def enum_certificates(store_name: str) -> _EnumRetType: ...
Expand Down Expand Up @@ -101,6 +104,12 @@ class _SSLContext:
def set_ciphers(self, cipherlist: str, /) -> None: ...
def set_default_verify_paths(self) -> None: ...
def set_ecdh_curve(self, name: str, /) -> None: ...
if sys.version_info >= (3, 15):
def get_groups(self, /, *, include_aliases: bool = False) -> list[str]: ...
def set_ciphersuites(self, ciphersuites: str, /) -> None: ...
def set_client_sigalgs(self, sigalgslist: str, /) -> None: ...
def set_groups(self, grouplist: str, /) -> None: ...
def set_server_sigalgs(self, sigalgslist: str, /) -> None: ...
if sys.version_info >= (3, 13):
def set_psk_client_callback(self, callback: Callable[[str | None], tuple[str | None, bytes]] | None) -> None: ...
def set_psk_server_callback(
Expand Down Expand Up @@ -271,6 +280,8 @@ HAS_ECDH: Final[bool]
HAS_NPN: Final[bool]
if sys.version_info >= (3, 13):
HAS_PSK: Final[bool]
if sys.version_info >= (3, 15):
HAS_PSK_TLS13: Final[bool]
HAS_ALPN: Final[bool]
HAS_SSLv2: Final[bool]
HAS_SSLv3: Final[bool]
Expand Down
46 changes: 41 additions & 5 deletions stdlib/argparse.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,28 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
_subparsers: _ArgumentGroup | None

# Note: the constructor arguments are also used in _SubParsersAction.add_parser.
if sys.version_info >= (3, 14):
if sys.version_info >= (3, 15):
def __init__(
self,
prog: str | None = None,
usage: str | None = None,
description: str | None = None,
epilog: str | None = None,
parents: Iterable[ArgumentParser] = [],
formatter_class: _FormatterClass = ...,
prefix_chars: str = "-",
fromfile_prefix_chars: str | None = None,
argument_default: Any = None,
conflict_handler: str = "error",
add_help: bool = True,
allow_abbrev: bool = True,
exit_on_error: bool = True,
*,
suggest_on_error: bool = True,
color: bool = True,
) -> None: ...

elif sys.version_info >= (3, 14):
def __init__(
self,
prog: str | None = None,
Expand Down Expand Up @@ -236,8 +257,14 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
) -> _SubParsersAction[_ArgumentParserT]: ...
def print_usage(self, file: SupportsWrite[str] | None = None) -> None: ...
def print_help(self, file: SupportsWrite[str] | None = None) -> None: ...
def format_usage(self) -> str: ...
def format_help(self) -> str: ...
if sys.version_info >= (3, 15):
def format_usage(self, formatter: HelpFormatter | None = None) -> str: ...
def format_help(self, formatter: HelpFormatter | None = None) -> str: ...

else:
def format_usage(self) -> str: ...
def format_help(self) -> str: ...

@overload
def parse_known_args(self, args: Iterable[str] | None = None, namespace: None = None) -> tuple[Namespace, list[str]]: ...
@overload
Expand Down Expand Up @@ -284,7 +311,11 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
def _get_values(self, action: Action, arg_strings: list[str]) -> Any: ...
def _get_value(self, action: Action, arg_string: str) -> Any: ...
def _check_value(self, action: Action, value: Any) -> None: ...
def _get_formatter(self) -> HelpFormatter: ...
if sys.version_info >= (3, 15):
def _get_formatter(self, file: SupportsWrite[str] | None = None) -> HelpFormatter: ...
else:
def _get_formatter(self) -> HelpFormatter: ...

def _print_message(self, message: str, file: SupportsWrite[str] | None = None) -> None: ...

class HelpFormatter:
Expand All @@ -309,7 +340,12 @@ class HelpFormatter:
def __init__(self, formatter: HelpFormatter, parent: Self | None, heading: str | None = None) -> None: ...
def format_help(self) -> str: ...

if sys.version_info >= (3, 14):
if sys.version_info >= (3, 15):
def __init__(
self, prog: str, indent_increment: int = 2, max_help_position: int = 24, width: int | None = None
) -> None: ...

elif sys.version_info >= (3, 14):
def __init__(
self, prog: str, indent_increment: int = 2, max_help_position: int = 24, width: int | None = None, color: bool = True
) -> None: ...
Expand Down
10 changes: 8 additions & 2 deletions stdlib/array.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ from typing import Any, ClassVar, Literal, SupportsIndex, TypeAlias, TypeVar, ov
from typing_extensions import Self, deprecated, disjoint_base

_IntTypeCode: TypeAlias = Literal["b", "B", "h", "H", "i", "I", "l", "L", "q", "Q"]
_FloatTypeCode: TypeAlias = Literal["f", "d"]
if sys.version_info >= (3, 15):
_FloatTypeCode: TypeAlias = Literal["f", "d", "e", "Zf", "Zd"]
else:
_FloatTypeCode: TypeAlias = Literal["f", "d"]
if sys.version_info >= (3, 13):
_UnicodeTypeCode: TypeAlias = Literal["u", "w"]
else:
Expand All @@ -15,7 +18,10 @@ _TypeCode: TypeAlias = _IntTypeCode | _FloatTypeCode | _UnicodeTypeCode

_T = TypeVar("_T", int, float, str)

typecodes: str
if sys.version_info >= (3, 15):
typecodes: tuple[str, ...]
else:
typecodes: str

@disjoint_base
class array(MutableSequence[_T]):
Expand Down
73 changes: 65 additions & 8 deletions stdlib/ast.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -710,22 +710,54 @@ class Assert(stmt):
def __replace__(self, *, test: expr = ..., msg: expr | None = ..., **kwargs: Unpack[_Attributes]) -> Self: ...

class Import(stmt):
__match_args__ = ("names",)
if sys.version_info >= (3, 15):
__match_args__ = ("names", "is_lazy")
elif sys.version_info >= (3, 10):
__match_args__ = ("names",)
names: list[alias]
if sys.version_info >= (3, 13):
if sys.version_info >= (3, 15):
is_lazy: bool | None
if sys.version_info >= (3, 15):
def __init__(self, names: list[alias] = ..., is_lazy: bool | None = None, **kwargs: Unpack[_Attributes]) -> None: ...

elif sys.version_info >= (3, 13):
def __init__(self, names: list[alias] = ..., **kwargs: Unpack[_Attributes]) -> None: ...
else:
def __init__(self, names: list[alias], **kwargs: Unpack[_Attributes]) -> None: ...

if sys.version_info >= (3, 14):
if sys.version_info >= (3, 15):
def __replace__(self, *, names: list[alias] = ..., is_lazy: bool | None = ..., **kwargs: Unpack[_Attributes]) -> Self: ...

elif sys.version_info >= (3, 14):
def __replace__(self, *, names: list[alias] = ..., **kwargs: Unpack[_Attributes]) -> Self: ...

class ImportFrom(stmt):
__match_args__ = ("module", "names", "level")
if sys.version_info >= (3, 15):
__match_args__ = ("module", "names", "level", "is_lazy")
elif sys.version_info >= (3, 10):
__match_args__ = ("module", "names", "level")
module: str | None
names: list[alias]
level: int
if sys.version_info >= (3, 13):
if sys.version_info >= (3, 15):
is_lazy: bool | None
if sys.version_info >= (3, 15):
@overload
def __init__(
self, module: str | None, names: list[alias], level: int, is_lazy: bool | None = None, **kwargs: Unpack[_Attributes]
) -> None: ...
@overload
def __init__(
self,
module: str | None = None,
names: list[alias] = ...,
*,
level: int,
is_lazy: bool | None = None,
**kwargs: Unpack[_Attributes],
) -> None: ...

elif sys.version_info >= (3, 13):
@overload
def __init__(self, module: str | None, names: list[alias], level: int, **kwargs: Unpack[_Attributes]) -> None: ...
@overload
Expand All @@ -740,7 +772,18 @@ class ImportFrom(stmt):
self, module: str | None = None, *, names: list[alias], level: int, **kwargs: Unpack[_Attributes]
) -> None: ...

if sys.version_info >= (3, 14):
if sys.version_info >= (3, 15):
def __replace__(
self,
*,
module: str | None = ...,
names: list[alias] = ...,
level: int = ...,
is_lazy: bool | None = ...,
**kwargs: Unpack[_Attributes],
) -> Self: ...

elif sys.version_info >= (3, 14):
def __replace__(
self, *, module: str | None = ..., names: list[alias] = ..., level: int = ..., **kwargs: Unpack[_Attributes]
) -> Self: ...
Expand Down Expand Up @@ -908,7 +951,10 @@ class SetComp(expr):
class DictComp(expr):
__match_args__ = ("key", "value", "generators")
key: expr
value: expr
if sys.version_info >= (3, 15):
value: expr | None
else:
value: expr
generators: list[comprehension]
if sys.version_info >= (3, 13):
def __init__(
Expand Down Expand Up @@ -1843,7 +1889,18 @@ else:

def literal_eval(node_or_string: str | AST) -> Any: ...

if sys.version_info >= (3, 13):
if sys.version_info >= (3, 15):
def dump(
node: AST,
annotate_fields: bool = True,
include_attributes: bool = False,
*,
indent: int | str | None = None,
show_empty: bool = False,
color: bool = False,
) -> str: ...

elif sys.version_info >= (3, 13):
def dump(
node: AST,
annotate_fields: bool = True,
Expand Down
Loading
Loading