Skip to content
Merged
Show file tree
Hide file tree
Changes from 24 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
3 changes: 3 additions & 0 deletions stdlib/@tests/stubtest_allowlists/common.txt
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,9 @@ unittest.runner._WritelnDecorator.write # Methods that come from __getattr__()
urllib.response.addbase.write # Methods that come from __getattr__() at runtime
urllib.response.addbase.writelines # Methods that come from __getattr__() at runtime

(pydoc.Doc.getdocloc)? # Runtime default is an installation-specific stdlib path.
(hashlib.__all__)? # scrypt depends on how OpenSSL was built.

_?weakref\.CallableProxyType\.__getattr__ # Should have all attributes of proxy
_?weakref\.(ref|ReferenceType)\.__init__ # C implementation has incorrect signature
_?weakref\.(ref|ReferenceType)\.__call__ # C function default annotation is wrong
Expand Down
1 change: 1 addition & 0 deletions stdlib/@tests/stubtest_allowlists/darwin.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ tkinter.Tk.deletefilehandler # Methods that come from __getattr__() at runtime

# These entries looks like a `setup-python` bug:
(dbm.gnu)?
(mmap.mmap.resize)?
(_?locale.bind_textdomain_codeset)?
(_?locale.bindtextdomain)?
(_?locale.dcgettext)?
Expand Down
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
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: 5 additions & 5 deletions stdlib/collections/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ from typing import Any, ClassVar, Generic, NoReturn, SupportsIndex, TypeVar, fin
from typing_extensions import Self, disjoint_base

if sys.version_info >= (3, 15):
from builtins import frozendict
from builtins import frozendict as _frozendict
Comment thread
JelleZijlstra marked this conversation as resolved.
Outdated

__all__ = ["ChainMap", "Counter", "OrderedDict", "UserDict", "UserList", "UserString", "defaultdict", "deque", "namedtuple"]

Expand Down Expand Up @@ -386,14 +386,14 @@ class OrderedDict(dict[_KT, _VT]):
def __eq__(self, value: object, /) -> bool: ...
if sys.version_info >= (3, 15):
@overload
def __or__(self, value: dict[_KT, _VT] | frozendict[_KT, _VT], /) -> Self: ...
def __or__(self, value: dict[_KT, _VT] | _frozendict[_KT, _VT], /) -> Self: ...
@overload
def __or__(self, value: dict[_T1, _T2] | frozendict[_T1, _T2], /) -> OrderedDict[_KT | _T1, _VT | _T2]: ...
def __or__(self, value: dict[_T1, _T2] | _frozendict[_T1, _T2], /) -> OrderedDict[_KT | _T1, _VT | _T2]: ...
@overload # type: ignore[override]
def __ror__(self, value: dict[_KT, _VT] | frozendict[_KT, _VT], /) -> Self: ... # type: ignore[override,misc]
def __ror__(self, value: dict[_KT, _VT] | _frozendict[_KT, _VT], /) -> Self: ... # type: ignore[override,misc]
@overload
def __ror__( # type: ignore[misc]
self, value: dict[_T1, _T2] | frozendict[_T1, _T2], /
self, value: dict[_T1, _T2] | _frozendict[_T1, _T2], /
) -> OrderedDict[_KT | _T1, _VT | _T2]: ...
else:
@overload
Expand Down
66 changes: 49 additions & 17 deletions stdlib/genericpath.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import sys
from _typeshed import BytesPath, FileDescriptorOrPath, StrOrBytesPath, StrPath, SupportsRichComparisonT
from collections.abc import Sequence
from typing import Literal, NewType, overload
from typing_extensions import LiteralString
from typing_extensions import LiteralString, deprecated

__all__ = [
"commonprefix",
Expand All @@ -23,22 +23,43 @@ if sys.version_info >= (3, 12):
__all__ += ["islink"]
if sys.version_info >= (3, 13):
__all__ += ["isjunction", "isdevdrive", "lexists"]
if sys.version_info >= (3, 15):
__all__ += ["ALL_BUT_LAST"]
ALL_BUT_LAST: object

# All overloads can return empty string. Ideally, Literal[""] would be a valid
# Iterable[T], so that list[T] | Literal[""] could be used as a return
# type. But because this only works when T is str, we need Sequence[T] instead.
@overload
def commonprefix(m: Sequence[LiteralString]) -> LiteralString: ...
@overload
def commonprefix(m: Sequence[StrPath]) -> str: ...
@overload
def commonprefix(m: Sequence[BytesPath]) -> bytes | Literal[""]: ...
@overload
def commonprefix(m: Sequence[list[SupportsRichComparisonT]]) -> Sequence[SupportsRichComparisonT]: ...
@overload
def commonprefix(m: Sequence[tuple[SupportsRichComparisonT, ...]]) -> Sequence[SupportsRichComparisonT]: ...
if sys.version_info >= (3, 15):
@overload
@deprecated("Deprecated since Python 3.15; use os.path.commonpath() for path prefixes.")
def commonprefix(m: Sequence[LiteralString], /) -> LiteralString: ...
@overload
@deprecated("Deprecated since Python 3.15; use os.path.commonpath() for path prefixes.")
def commonprefix(m: Sequence[StrPath], /) -> str: ...
@overload
@deprecated("Deprecated since Python 3.15; use os.path.commonpath() for path prefixes.")
def commonprefix(m: Sequence[BytesPath], /) -> bytes | Literal[""]: ...
@overload
@deprecated("Deprecated since Python 3.15; use os.path.commonpath() for path prefixes.")
def commonprefix(m: Sequence[list[SupportsRichComparisonT]], /) -> Sequence[SupportsRichComparisonT]: ...
@overload
@deprecated("Deprecated since Python 3.15; use os.path.commonpath() for path prefixes.")
def commonprefix(m: Sequence[tuple[SupportsRichComparisonT, ...]], /) -> Sequence[SupportsRichComparisonT]: ...

else:
@overload
def commonprefix(m: Sequence[LiteralString]) -> LiteralString: ...
@overload
def commonprefix(m: Sequence[StrPath]) -> str: ...
@overload
def commonprefix(m: Sequence[BytesPath]) -> bytes | Literal[""]: ...
@overload
def commonprefix(m: Sequence[list[SupportsRichComparisonT]]) -> Sequence[SupportsRichComparisonT]: ...
@overload
def commonprefix(m: Sequence[tuple[SupportsRichComparisonT, ...]]) -> Sequence[SupportsRichComparisonT]: ...

def exists(path: FileDescriptorOrPath) -> bool: ...
def getsize(filename: FileDescriptorOrPath) -> int: ...
def isfile(path: FileDescriptorOrPath) -> bool: ...
def isdir(s: FileDescriptorOrPath) -> bool: ...

Expand All @@ -47,12 +68,23 @@ if sys.version_info >= (3, 12):

# These return float if os.stat_float_times() == True,
# but int is a subclass of float.
def getatime(filename: FileDescriptorOrPath) -> float: ...
def getmtime(filename: FileDescriptorOrPath) -> float: ...
def getctime(filename: FileDescriptorOrPath) -> float: ...
def samefile(f1: FileDescriptorOrPath, f2: FileDescriptorOrPath) -> bool: ...
def sameopenfile(fp1: int, fp2: int) -> bool: ...
def samestat(s1: os.stat_result, s2: os.stat_result) -> bool: ...

if sys.version_info >= (3, 15):
def getsize(filename: FileDescriptorOrPath, /) -> int: ...
def getatime(filename: FileDescriptorOrPath, /) -> float: ...
def getmtime(filename: FileDescriptorOrPath, /) -> float: ...
def getctime(filename: FileDescriptorOrPath, /) -> float: ...
def samefile(f1: FileDescriptorOrPath, f2: FileDescriptorOrPath, /) -> bool: ...
def samestat(s1: os.stat_result, s2: os.stat_result, /) -> bool: ...

else:
def getsize(filename: FileDescriptorOrPath) -> int: ...
def getatime(filename: FileDescriptorOrPath) -> float: ...
def getmtime(filename: FileDescriptorOrPath) -> float: ...
def getctime(filename: FileDescriptorOrPath) -> float: ...
def samefile(f1: FileDescriptorOrPath, f2: FileDescriptorOrPath) -> bool: ...
def samestat(s1: os.stat_result, s2: os.stat_result) -> bool: ...

if sys.version_info >= (3, 13):
def isjunction(path: StrOrBytesPath) -> bool: ...
Expand Down
19 changes: 11 additions & 8 deletions stdlib/glob.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ __all__ = ["escape", "glob", "iglob"]
if sys.version_info >= (3, 13):
__all__ += ["translate"]

@deprecated(
"Deprecated since Python 3.10; will be removed in Python 3.15. Use `glob.glob()` with the *root_dir* argument instead."
)
def glob0(dirname: AnyStr, pattern: AnyStr) -> list[AnyStr]: ...
@deprecated(
"Deprecated since Python 3.10; will be removed in Python 3.15. Use `glob.glob()` with the *root_dir* argument instead."
)
def glob1(dirname: AnyStr, pattern: AnyStr) -> list[AnyStr]: ...
if sys.version_info >= (3, 15):
pass
else:
@deprecated(
"Deprecated since Python 3.10; will be removed in Python 3.15. Use `glob.glob()` with the *root_dir* argument instead."
)
def glob0(dirname: AnyStr, pattern: AnyStr) -> list[AnyStr]: ...
@deprecated(
"Deprecated since Python 3.10; will be removed in Python 3.15. Use `glob.glob()` with the *root_dir* argument instead."
)
def glob1(dirname: AnyStr, pattern: AnyStr) -> list[AnyStr]: ...

if sys.version_info >= (3, 11):
def glob(
Expand Down
43 changes: 34 additions & 9 deletions stdlib/http/client.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -178,14 +178,27 @@ class HTTPConnection:
host: str
port: int
sock: socket | MaybeNone # can be `None` if `.connect()` was not called
def __init__(
self,
host: str,
port: int | None = None,
timeout: float | None = ...,
source_address: tuple[str, int] | None = None,
blocksize: int = 8192,
) -> None: ...
if sys.version_info >= (3, 15):
def __init__(
self,
host: str,
port: int | None = None,
timeout: float | None = ...,
source_address: tuple[str, int] | None = None,
blocksize: int = 8192,
*,
max_response_headers: int | None = None,
) -> None: ...
else:
def __init__(
self,
host: str,
port: int | None = None,
timeout: float | None = ...,
source_address: tuple[str, int] | None = None,
blocksize: int = 8192,
) -> None: ...

def request(
self,
method: str,
Expand All @@ -211,7 +224,19 @@ class HTTPConnection:
class HTTPSConnection(HTTPConnection):
# Can be `None` if `.connect()` was not called:
sock: ssl.SSLSocket | MaybeNone
if sys.version_info >= (3, 12):
if sys.version_info >= (3, 15):
def __init__(
self,
host: str,
port: int | None = None,
*,
timeout: float | None = ...,
source_address: tuple[str, int] | None = None,
context: ssl.SSLContext | None = None,
blocksize: int = 8192,
max_response_headers: int | None = None,
) -> None: ...
elif sys.version_info >= (3, 12):
def __init__(
self,
host: str,
Expand Down
45 changes: 35 additions & 10 deletions stdlib/http/server.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,16 @@ from ssl import Purpose, SSLContext
from typing import Any, AnyStr, BinaryIO, ClassVar, Protocol, type_check_only
from typing_extensions import Self, deprecated

if sys.version_info >= (3, 14):
if sys.version_info >= (3, 15):
__all__ = [
"HTTPServer",
"ThreadingHTTPServer",
"HTTPSServer",
"ThreadingHTTPSServer",
"BaseHTTPRequestHandler",
"SimpleHTTPRequestHandler",
]
elif sys.version_info >= (3, 14):
__all__ = [
"HTTPServer",
"ThreadingHTTPServer",
Expand Down Expand Up @@ -77,6 +86,8 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
protocol_version: str
MessageClass: type
responses: Mapping[int, tuple[str, str]]
if sys.version_info >= (3, 15):
default_content_type: str
default_request_version: str # undocumented
weekdayname: ClassVar[Sequence[str]] # undocumented
monthname: ClassVar[Sequence[str | None]] # undocumented
Expand All @@ -102,14 +113,26 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
if sys.version_info >= (3, 12):
index_pages: ClassVar[tuple[str, ...]]
directory: str
def __init__(
self,
request: socketserver._RequestType,
client_address: _socket._RetAddress,
server: socketserver.BaseServer,
*,
directory: StrPath | None = None,
) -> None: ...
if sys.version_info >= (3, 15):
def __init__(
self,
request: socketserver._RequestType,
client_address: _socket._RetAddress,
server: socketserver.BaseServer,
*,
directory: StrPath | None = None,
extra_response_headers: Mapping[str, str] | None = None,
) -> None: ...
else:
def __init__(
self,
request: socketserver._RequestType,
client_address: _socket._RetAddress,
server: socketserver.BaseServer,
*,
directory: StrPath | None = None,
) -> None: ...

def do_GET(self) -> None: ...
def do_HEAD(self) -> None: ...
def send_head(self) -> io.BytesIO | BinaryIO | None: ... # undocumented
Expand All @@ -120,7 +143,9 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):

def executable(path: StrPath) -> bool: ... # undocumented

if sys.version_info >= (3, 13):
if sys.version_info >= (3, 15):
pass
elif sys.version_info >= (3, 13):
@deprecated("Deprecated since Python 3.13; will be removed in Python 3.15.")
class CGIHTTPRequestHandler(SimpleHTTPRequestHandler):
cgi_directories: list[str]
Expand Down
10 changes: 9 additions & 1 deletion stdlib/importlib/metadata/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ __all__ = [
"version",
]

if sys.version_info >= (3, 15):
__all__ += ["PackagePath", "MetadataNotFound", "SimplePath"]

_SimplePath: TypeAlias = SimplePath

def packages_distributions() -> Mapping[str, list[str]]: ...
Expand All @@ -39,6 +42,9 @@ class PackageNotFoundError(ModuleNotFoundError):
@property
def name(self) -> str: ... # type: ignore[override]

if sys.version_info >= (3, 15):
class MetadataNotFound(FileNotFoundError): ...

if sys.version_info >= (3, 13):
_EntryPointBase = object
elif sys.version_info >= (3, 11):
Expand Down Expand Up @@ -203,7 +209,9 @@ class FileHash:
value: str
def __init__(self, spec: str) -> None: ...

if sys.version_info >= (3, 12):
if sys.version_info >= (3, 15):
_distribution_parent = abc.ABC
elif sys.version_info >= (3, 12):
class DeprecatedNonAbstract: ...
_distribution_parent = DeprecatedNonAbstract
else:
Expand Down
Loading
Loading