From 9ae869f5a9da9a7987d39fbd07dee9b15dd0baef Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Wed, 24 Jun 2026 13:27:14 +0200 Subject: [PATCH 1/5] Update to Python 3.15b3 --- stdlib/VERSIONS | 2 - stdlib/_curses.pyi | 73 ++++++++++--- stdlib/profiling/sampling/gecko_collector.pyi | 102 +++++++++++++++++- 3 files changed, 157 insertions(+), 20 deletions(-) diff --git a/stdlib/VERSIONS b/stdlib/VERSIONS index e9c8d91fdbd7..96eb98131db6 100644 --- a/stdlib/VERSIONS +++ b/stdlib/VERSIONS @@ -245,8 +245,6 @@ 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- diff --git a/stdlib/_curses.pyi b/stdlib/_curses.pyi index 449cf75dad42..aebd995f1f0c 100644 --- a/stdlib/_curses.pyi +++ b/stdlib/_curses.pyi @@ -423,7 +423,12 @@ class window: # undocumented def chgat(self, y: int, x: int, num: int, attr: int) -> None: ... def clear(self) -> None: ... - def clearok(self, yes: int) -> None: ... + + if sys.version_info >= (3, 15): + def clearok(self, flag: bool, /) -> None: ... + else: + def clearok(self, yes: int) -> None: ... + def clrtobot(self) -> None: ... def clrtoeol(self) -> None: ... def cursyncup(self) -> None: ... @@ -480,9 +485,14 @@ class window: # undocumented @overload def hline(self, y: int, x: int, ch: _ChType, n: int) -> None: ... - def idcok(self, flag: bool) -> None: ... - def idlok(self, yes: bool) -> None: ... - def immedok(self, flag: bool) -> None: ... + if sys.version_info >= (3, 15): + def idcok(self, flag: bool, /) -> None: ... + def idlok(self, flag: bool, /) -> None: ... + def immedok(self, flag: bool, /) -> None: ... + else: + def idcok(self, flag: bool) -> None: ... + def idlok(self, yes: bool) -> None: ... + def immedok(self, flag: bool) -> None: ... @overload def inch(self) -> int: ... @@ -494,7 +504,11 @@ class window: # undocumented @overload def insch(self, y: int, x: int, ch: _ChType, attr: int = ...) -> None: ... - def insdelln(self, nlines: int) -> None: ... + if sys.version_info >= (3, 15): + def insdelln(self, nlines: int, /) -> None: ... + else: + def insdelln(self, nlines: int) -> None: ... + def insertln(self) -> None: ... @overload @@ -514,13 +528,23 @@ class window: # undocumented def is_linetouched(self, line: int, /) -> bool: ... def is_wintouched(self) -> bool: ... - def keypad(self, yes: bool, /) -> None: ... - def leaveok(self, yes: bool) -> None: ... - def move(self, new_y: int, new_x: int) -> None: ... - def mvderwin(self, y: int, x: int) -> None: ... - def mvwin(self, new_y: int, new_x: int) -> None: ... - def nodelay(self, yes: bool) -> None: ... - def notimeout(self, yes: bool) -> None: ... + + if sys.version_info >= (3, 15): + def keypad(self, flag: bool, /) -> None: ... + def leaveok(self, flag: bool, /) -> None: ... + def move(self, new_y: int, new_x: int, /) -> None: ... + def mvderwin(self, y: int, x: int, /) -> None: ... + def mvwin(self, new_y: int, new_x: int, /) -> None: ... + def nodelay(self, flag: bool, /) -> None: ... + def notimeout(self, flag: bool, /) -> None: ... + else: + def keypad(self, yes: bool, /) -> None: ... + def leaveok(self, yes: bool) -> None: ... + def move(self, new_y: int, new_x: int) -> None: ... + def mvderwin(self, y: int, x: int) -> None: ... + def mvwin(self, new_y: int, new_x: int) -> None: ... + def nodelay(self, yes: bool) -> None: ... + def notimeout(self, yes: bool) -> None: ... @overload def noutrefresh(self) -> None: ... @@ -550,9 +574,18 @@ class window: # undocumented @overload def refresh(self, pminrow: int, pmincol: int, sminrow: int, smincol: int, smaxrow: int, smaxcol: int) -> None: ... - def resize(self, nlines: int, ncols: int) -> None: ... + if sys.version_info >= (3, 15): + def resize(self, nlines: int, ncols: int, /) -> None: ... + else: + def resize(self, nlines: int, ncols: int) -> None: ... + def scroll(self, lines: int = 1) -> None: ... - def scrollok(self, flag: bool) -> None: ... + + if sys.version_info >= (3, 15): + def scrollok(self, flag: bool, /) -> None: ... + else: + def scrollok(self, flag: bool) -> None: ... + def setscrreg(self, top: int, bottom: int, /) -> None: ... def standend(self) -> None: ... def standout(self) -> None: ... @@ -568,9 +601,17 @@ class window: # undocumented def subwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> window: ... def syncdown(self) -> None: ... - def syncok(self, flag: bool) -> None: ... + if sys.version_info >= (3, 15): + def syncok(self, flag: bool, /) -> None: ... + else: + def syncok(self, flag: bool) -> None: ... + def syncup(self) -> None: ... - def timeout(self, delay: int) -> None: ... + if sys.version_info >= (3, 15): + def timeout(self, delay: int, /) -> None: ... + else: + def timeout(self, delay: int) -> None: ... + def touchline(self, start: int, count: int, changed: bool = True) -> None: ... def touchwin(self) -> None: ... def untouchwin(self) -> None: ... diff --git a/stdlib/profiling/sampling/gecko_collector.pyi b/stdlib/profiling/sampling/gecko_collector.pyi index 6072d4f2359a..a93315f99521 100644 --- a/stdlib/profiling/sampling/gecko_collector.pyi +++ b/stdlib/profiling/sampling/gecko_collector.pyi @@ -1,11 +1,109 @@ -from _typeshed import StrOrBytesPath -from collections.abc import Sequence +from _typeshed import Incomplete, StrOrBytesPath, StrPath +from collections.abc import Generator, Sequence +from tempfile import TemporaryDirectory +from typing import Any, ClassVar, Final, TypedDict, type_check_only from _remote_debugging import AwaitedInfo, InterpreterInfo from .collector import Collector, _Timestamps +@type_check_only +class _GeckoCategory(TypedDict): + name: str + color: str + subcategories: list[str] + +THREAD_STATUS_HAS_GIL: Final[int] +THREAD_STATUS_ON_CPU: Final[int] +THREAD_STATUS_UNKNOWN: Final[int] +THREAD_STATUS_GIL_REQUESTED: Final[int] +THREAD_STATUS_HAS_EXCEPTION: Final[int] +THREAD_STATUS_MAIN_THREAD: Final[int] + +GECKO_CATEGORIES: Final[list[_GeckoCategory]] + +CATEGORY_OTHER: Final = 0 +CATEGORY_PYTHON: Final = 1 +CATEGORY_NATIVE: Final = 2 +CATEGORY_GC: Final = 3 +CATEGORY_GIL: Final = 4 +CATEGORY_CPU: Final = 5 +CATEGORY_CODE_TYPE: Final = 6 +CATEGORY_OPCODES: Final = 7 +CATEGORY_EXCEPTION: Final = 8 + +DEFAULT_SUBCATEGORY: Final = 0 + +GECKO_FORMAT_VERSION: Final = 32 +GECKO_PREPROCESSED_VERSION: Final = 57 + +RESOURCE_TYPE_LIBRARY: Final = 1 + +FRAME_ADDRESS_NONE: Final = -1 +FRAME_INLINE_DEPTH_ROOT: Final = 0 + +PROCESS_TYPE_MAIN: Final = 0 +STACKWALK_DISABLED: Final = 0 + +DEFAULT_SPILL_BUFFER_BYTES: Final[int] + +class SpillColumn: + path: str + buffer: bytearray + + def __init__(self, directory: StrPath, basename: StrPath, *, buffer_bytes: int | None = None) -> None: ... + # "value" accepts the same types as json.JSONEncoder.encode() + def append(self, value: Any) -> None: ... + def flush(self) -> None: ... + def iter_tokens(self) -> Generator[str]: ... + +class GeckoThreadSpill: + sample_count: int + marker_count: int + def __init__(self, directory: StrPath, tid: int) -> None: ... + def append_sample(self, stack_index: int, time_ms: float) -> None: ... + def append_marker( + self, name_idx: int, start_time: float, end_time: float, phase: int, category: int, data: dict[str, Any] + ) -> None: ... + def prepare_read(self) -> None: ... + class GeckoCollector(Collector): + aggregating: ClassVar[bool] + + sample_interval_usec: int + skip_idle: bool + opcodes_enabled: bool + start_time: float + + global_strings: list[str] + global_string_map: dict[str, int] + + threads: dict[int, dict[str, Any]] + spill_dir: TemporaryDirectory[str] | None + exported: bool + + libs: list[Incomplete] + + sample_count: int + last_sample_time: float + interval: float + + has_gil_start: dict[Incomplete, Incomplete] + no_gil_start = dict[Incomplete, Incomplete] + on_cpu_start = dict[Incomplete, Incomplete] + off_cpu_start = dict[Incomplete, Incomplete] + python_code_start = dict[Incomplete, Incomplete] + native_code_start = dict[Incomplete, Incomplete] + gil_wait_start = dict[Incomplete, Incomplete] + exception_start = dict[Incomplete, Incomplete] + no_exception_start = dict[Incomplete, Incomplete] + + gc_start_per_thread: dict[int, float] + + initialized_threads: set[Incomplete] + + opcode_state: dict[int, tuple[Incomplete, int, int, str, str, float]] + def __init__(self, sample_interval_usec: int, *, skip_idle: bool = False, opcodes: bool = False) -> None: ... def collect( self, stack_frames: Sequence[InterpreterInfo] | Sequence[AwaitedInfo], timestamps_us: _Timestamps = None From d5cc14266a68e894a7ecf9eee0b4e23a20d81030 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 24 Jun 2026 11:29:50 +0000 Subject: [PATCH 2/5] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/profiling/sampling/gecko_collector.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/profiling/sampling/gecko_collector.pyi b/stdlib/profiling/sampling/gecko_collector.pyi index a93315f99521..541fd2b3ba95 100644 --- a/stdlib/profiling/sampling/gecko_collector.pyi +++ b/stdlib/profiling/sampling/gecko_collector.pyi @@ -79,7 +79,7 @@ class GeckoCollector(Collector): global_string_map: dict[str, int] threads: dict[int, dict[str, Any]] - spill_dir: TemporaryDirectory[str] | None + spill_dir: TemporaryDirectory[str] | None exported: bool libs: list[Incomplete] From 0f21c5f41eed90683c38d2d06bd5f12063bbcb7a Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Wed, 24 Jun 2026 13:33:00 +0200 Subject: [PATCH 3/5] Fix "type aliases" --- stdlib/profiling/sampling/gecko_collector.pyi | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/stdlib/profiling/sampling/gecko_collector.pyi b/stdlib/profiling/sampling/gecko_collector.pyi index 541fd2b3ba95..666fd42c3ea5 100644 --- a/stdlib/profiling/sampling/gecko_collector.pyi +++ b/stdlib/profiling/sampling/gecko_collector.pyi @@ -89,14 +89,14 @@ class GeckoCollector(Collector): interval: float has_gil_start: dict[Incomplete, Incomplete] - no_gil_start = dict[Incomplete, Incomplete] - on_cpu_start = dict[Incomplete, Incomplete] - off_cpu_start = dict[Incomplete, Incomplete] - python_code_start = dict[Incomplete, Incomplete] - native_code_start = dict[Incomplete, Incomplete] - gil_wait_start = dict[Incomplete, Incomplete] - exception_start = dict[Incomplete, Incomplete] - no_exception_start = dict[Incomplete, Incomplete] + no_gil_start: dict[Incomplete, Incomplete] + on_cpu_start: dict[Incomplete, Incomplete] + off_cpu_start: dict[Incomplete, Incomplete] + python_code_start: dict[Incomplete, Incomplete] + native_code_start: dict[Incomplete, Incomplete] + gil_wait_start: dict[Incomplete, Incomplete] + exception_start: dict[Incomplete, Incomplete] + no_exception_start: dict[Incomplete, Incomplete] gc_start_per_thread: dict[int, float] From 81be658d2e1d7f0bee4f4dfe8f57349f6cfab36d Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Wed, 24 Jun 2026 13:33:56 +0200 Subject: [PATCH 4/5] Remove allowlist entries --- stdlib/@tests/stubtest_allowlists/py315.txt | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/stdlib/@tests/stubtest_allowlists/py315.txt b/stdlib/@tests/stubtest_allowlists/py315.txt index b225bfc4924a..a81be4ae2e8a 100644 --- a/stdlib/@tests/stubtest_allowlists/py315.txt +++ b/stdlib/@tests/stubtest_allowlists/py315.txt @@ -56,24 +56,6 @@ profiling.sampling.cli profiling.sampling.constants profiling.sampling.dump profiling.sampling.errors -profiling.sampling.gecko_collector.CATEGORY_CODE_TYPE -profiling.sampling.gecko_collector.CATEGORY_CPU -profiling.sampling.gecko_collector.CATEGORY_EXCEPTION -profiling.sampling.gecko_collector.CATEGORY_GC -profiling.sampling.gecko_collector.CATEGORY_GIL -profiling.sampling.gecko_collector.CATEGORY_NATIVE -profiling.sampling.gecko_collector.CATEGORY_OPCODES -profiling.sampling.gecko_collector.CATEGORY_OTHER -profiling.sampling.gecko_collector.CATEGORY_PYTHON -profiling.sampling.gecko_collector.DEFAULT_SUBCATEGORY -profiling.sampling.gecko_collector.FRAME_ADDRESS_NONE -profiling.sampling.gecko_collector.FRAME_INLINE_DEPTH_ROOT -profiling.sampling.gecko_collector.GECKO_CATEGORIES -profiling.sampling.gecko_collector.GECKO_FORMAT_VERSION -profiling.sampling.gecko_collector.GECKO_PREPROCESSED_VERSION -profiling.sampling.gecko_collector.PROCESS_TYPE_MAIN -profiling.sampling.gecko_collector.RESOURCE_TYPE_LIBRARY -profiling.sampling.gecko_collector.STACKWALK_DISABLED profiling.sampling.heatmap_collector.FileStats profiling.sampling.heatmap_collector.TreeNode profiling.sampling.module_utils From e4f256bab145838392c08a2a37599f04570a4873 Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Wed, 24 Jun 2026 14:57:02 +0200 Subject: [PATCH 5/5] Remove version guards --- stdlib/_curses.pyi | 73 ++++++++++------------------------------------ 1 file changed, 16 insertions(+), 57 deletions(-) diff --git a/stdlib/_curses.pyi b/stdlib/_curses.pyi index aebd995f1f0c..fcd0da4c465c 100644 --- a/stdlib/_curses.pyi +++ b/stdlib/_curses.pyi @@ -423,12 +423,7 @@ class window: # undocumented def chgat(self, y: int, x: int, num: int, attr: int) -> None: ... def clear(self) -> None: ... - - if sys.version_info >= (3, 15): - def clearok(self, flag: bool, /) -> None: ... - else: - def clearok(self, yes: int) -> None: ... - + def clearok(self, flag: bool, /) -> None: ... def clrtobot(self) -> None: ... def clrtoeol(self) -> None: ... def cursyncup(self) -> None: ... @@ -485,14 +480,9 @@ class window: # undocumented @overload def hline(self, y: int, x: int, ch: _ChType, n: int) -> None: ... - if sys.version_info >= (3, 15): - def idcok(self, flag: bool, /) -> None: ... - def idlok(self, flag: bool, /) -> None: ... - def immedok(self, flag: bool, /) -> None: ... - else: - def idcok(self, flag: bool) -> None: ... - def idlok(self, yes: bool) -> None: ... - def immedok(self, flag: bool) -> None: ... + def idcok(self, flag: bool, /) -> None: ... + def idlok(self, flag: bool, /) -> None: ... + def immedok(self, flag: bool, /) -> None: ... @overload def inch(self) -> int: ... @@ -504,11 +494,7 @@ class window: # undocumented @overload def insch(self, y: int, x: int, ch: _ChType, attr: int = ...) -> None: ... - if sys.version_info >= (3, 15): - def insdelln(self, nlines: int, /) -> None: ... - else: - def insdelln(self, nlines: int) -> None: ... - + def insdelln(self, nlines: int, /) -> None: ... def insertln(self) -> None: ... @overload @@ -528,23 +514,13 @@ class window: # undocumented def is_linetouched(self, line: int, /) -> bool: ... def is_wintouched(self) -> bool: ... - - if sys.version_info >= (3, 15): - def keypad(self, flag: bool, /) -> None: ... - def leaveok(self, flag: bool, /) -> None: ... - def move(self, new_y: int, new_x: int, /) -> None: ... - def mvderwin(self, y: int, x: int, /) -> None: ... - def mvwin(self, new_y: int, new_x: int, /) -> None: ... - def nodelay(self, flag: bool, /) -> None: ... - def notimeout(self, flag: bool, /) -> None: ... - else: - def keypad(self, yes: bool, /) -> None: ... - def leaveok(self, yes: bool) -> None: ... - def move(self, new_y: int, new_x: int) -> None: ... - def mvderwin(self, y: int, x: int) -> None: ... - def mvwin(self, new_y: int, new_x: int) -> None: ... - def nodelay(self, yes: bool) -> None: ... - def notimeout(self, yes: bool) -> None: ... + def keypad(self, flag: bool, /) -> None: ... + def leaveok(self, flag: bool, /) -> None: ... + def move(self, new_y: int, new_x: int, /) -> None: ... + def mvderwin(self, y: int, x: int, /) -> None: ... + def mvwin(self, new_y: int, new_x: int, /) -> None: ... + def nodelay(self, flag: bool, /) -> None: ... + def notimeout(self, flag: bool, /) -> None: ... @overload def noutrefresh(self) -> None: ... @@ -574,18 +550,9 @@ class window: # undocumented @overload def refresh(self, pminrow: int, pmincol: int, sminrow: int, smincol: int, smaxrow: int, smaxcol: int) -> None: ... - if sys.version_info >= (3, 15): - def resize(self, nlines: int, ncols: int, /) -> None: ... - else: - def resize(self, nlines: int, ncols: int) -> None: ... - + def resize(self, nlines: int, ncols: int, /) -> None: ... def scroll(self, lines: int = 1) -> None: ... - - if sys.version_info >= (3, 15): - def scrollok(self, flag: bool, /) -> None: ... - else: - def scrollok(self, flag: bool) -> None: ... - + def scrollok(self, flag: bool, /) -> None: ... def setscrreg(self, top: int, bottom: int, /) -> None: ... def standend(self) -> None: ... def standout(self) -> None: ... @@ -601,17 +568,9 @@ class window: # undocumented def subwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> window: ... def syncdown(self) -> None: ... - if sys.version_info >= (3, 15): - def syncok(self, flag: bool, /) -> None: ... - else: - def syncok(self, flag: bool) -> None: ... - + def syncok(self, flag: bool, /) -> None: ... def syncup(self) -> None: ... - if sys.version_info >= (3, 15): - def timeout(self, delay: int, /) -> None: ... - else: - def timeout(self, delay: int) -> None: ... - + def timeout(self, delay: int, /) -> None: ... def touchline(self, start: int, count: int, changed: bool = True) -> None: ... def touchwin(self) -> None: ... def untouchwin(self) -> None: ...