From 3fa1425bfbab1cb7a4e0bd9c92483f11dccd1181 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Mon, 8 Dec 2025 02:51:51 +0200 Subject: [PATCH 1/3] gh-142363: Improve Tachyon flamegraph contrast (#142377) --- Lib/profiling/sampling/_flamegraph_assets/flamegraph.css | 2 +- Lib/profiling/sampling/_shared_assets/base.css | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.css b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.css index c75f2324b6d499..18d2279da9b645 100644 --- a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.css +++ b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.css @@ -789,7 +789,7 @@ body.resizing-sidebar { .tooltip-location { font-family: var(--font-mono); font-size: 11px; - color: var(--text-muted); + color: var(--text-secondary); background: var(--bg-tertiary); padding: 4px 8px; border-radius: 4px; diff --git a/Lib/profiling/sampling/_shared_assets/base.css b/Lib/profiling/sampling/_shared_assets/base.css index d9223a98c0f756..54e3d78f8ebf34 100644 --- a/Lib/profiling/sampling/_shared_assets/base.css +++ b/Lib/profiling/sampling/_shared_assets/base.css @@ -44,7 +44,7 @@ --text-primary: #2e3338; --text-secondary: #5a6c7d; - --text-muted: #8b949e; + --text-muted: #6f767e; --accent: #3776ab; --accent-hover: #2d5aa0; @@ -91,7 +91,7 @@ --text-primary: #e6edf3; --text-secondary: #8b949e; - --text-muted: #6e7681; + --text-muted: #757e8a; --accent: #58a6ff; --accent-hover: #79b8ff; From 7099af8f5e6966bc0179b74c8306506d892282e7 Mon Sep 17 00:00:00 2001 From: Frost Ming Date: Mon, 8 Dec 2025 12:08:06 +0800 Subject: [PATCH 2/3] gh-139946: distinguish stdout or stderr when colorizing output in argparse (#140495) Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Savannah Ostrowski --- Lib/argparse.py | 44 +++++++++++++------ Lib/test/test_argparse.py | 34 ++++++++++++++ ...-10-23-06-38-35.gh-issue-139946.HZa5hu.rst | 1 + 3 files changed, 65 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-10-23-06-38-35.gh-issue-139946.HZa5hu.rst diff --git a/Lib/argparse.py b/Lib/argparse.py index 398825508f5917..1d550264ae420f 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -89,8 +89,8 @@ import os as _os import re as _re import sys as _sys - -from gettext import gettext as _, ngettext +from gettext import gettext as _ +from gettext import ngettext SUPPRESS = '==SUPPRESS==' @@ -191,10 +191,10 @@ def __init__( self._set_color(False) - def _set_color(self, color): + def _set_color(self, color, *, file=None): from _colorize import can_colorize, decolor, get_theme - if color and can_colorize(): + if color and can_colorize(file=file): self._theme = get_theme(force_color=True).argparse self._decolor = decolor else: @@ -1675,7 +1675,7 @@ def _get_optional_kwargs(self, *args, **kwargs): option_strings = [] for option_string in args: # error on strings that don't start with an appropriate prefix - if not option_string[0] in self.prefix_chars: + if option_string[0] not in self.prefix_chars: raise ValueError( f'invalid option string {option_string!r}: ' f'must start with a character {self.prefix_chars!r}') @@ -2455,7 +2455,7 @@ def _parse_optional(self, arg_string): return None # if it doesn't start with a prefix, it was meant to be positional - if not arg_string[0] in self.prefix_chars: + if arg_string[0] not in self.prefix_chars: return None # if the option string is present in the parser, return the action @@ -2717,14 +2717,16 @@ def _check_value(self, action, value): # Help-formatting methods # ======================= - def format_usage(self): - formatter = self._get_formatter() + def format_usage(self, formatter=None): + if formatter is None: + formatter = self._get_formatter() formatter.add_usage(self.usage, self._actions, self._mutually_exclusive_groups) return formatter.format_help() - def format_help(self): - formatter = self._get_formatter() + def format_help(self, formatter=None): + if formatter is None: + formatter = self._get_formatter() # usage formatter.add_usage(self.usage, self._actions, @@ -2746,9 +2748,9 @@ def format_help(self): # determine help from format above return formatter.format_help() - def _get_formatter(self): + def _get_formatter(self, file=None): formatter = self.formatter_class(prog=self.prog) - formatter._set_color(self.color) + formatter._set_color(self.color, file=file) return formatter def _get_validation_formatter(self): @@ -2765,12 +2767,26 @@ def _get_validation_formatter(self): def print_usage(self, file=None): if file is None: file = _sys.stdout - self._print_message(self.format_usage(), file) + formatter = self._get_formatter(file=file) + try: + usage_text = self.format_usage(formatter=formatter) + except TypeError: + # Backward compatibility for formatter classes that + # do not accept the 'formatter' keyword argument. + usage_text = self.format_usage() + self._print_message(usage_text, file) def print_help(self, file=None): if file is None: file = _sys.stdout - self._print_message(self.format_help(), file) + formatter = self._get_formatter(file=file) + try: + help_text = self.format_help(formatter=formatter) + except TypeError: + # Backward compatibility for formatter classes that + # do not accept the 'formatter' keyword argument. + help_text = self.format_help() + self._print_message(help_text, file) def _print_message(self, message, file=None): if message: diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 7c5eed21219de0..ab5382e41e7871 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -7558,6 +7558,40 @@ def test_error_and_warning_not_colorized_when_disabled(self): self.assertNotIn('\x1b[', warn) self.assertIn('warning:', warn) + def test_print_help_uses_target_file_for_color_decision(self): + parser = argparse.ArgumentParser(prog='PROG', color=True) + parser.add_argument('--opt') + output = io.StringIO() + calls = [] + + def fake_can_colorize(*, file=None): + calls.append(file) + return file is None + + with swap_attr(_colorize, 'can_colorize', fake_can_colorize): + parser.print_help(file=output) + + self.assertIs(calls[-1], output) + self.assertIn(output, calls) + self.assertNotIn('\x1b[', output.getvalue()) + + def test_print_usage_uses_target_file_for_color_decision(self): + parser = argparse.ArgumentParser(prog='PROG', color=True) + parser.add_argument('--opt') + output = io.StringIO() + calls = [] + + def fake_can_colorize(*, file=None): + calls.append(file) + return file is None + + with swap_attr(_colorize, 'can_colorize', fake_can_colorize): + parser.print_usage(file=output) + + self.assertIs(calls[-1], output) + self.assertIn(output, calls) + self.assertNotIn('\x1b[', output.getvalue()) + class TestModule(unittest.TestCase): def test_deprecated__version__(self): diff --git a/Misc/NEWS.d/next/Library/2025-10-23-06-38-35.gh-issue-139946.HZa5hu.rst b/Misc/NEWS.d/next/Library/2025-10-23-06-38-35.gh-issue-139946.HZa5hu.rst new file mode 100644 index 00000000000000..fb47931728414d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-10-23-06-38-35.gh-issue-139946.HZa5hu.rst @@ -0,0 +1 @@ +Distinguish stdout and stderr when colorizing output in argparse module. From 3db7bf2d180be5475266411b62114c28a0d4f92c Mon Sep 17 00:00:00 2001 From: yihong Date: Mon, 8 Dec 2025 12:45:04 +0800 Subject: [PATCH 3/3] gh-142207: remove assertions incompatible under `profiling.sampling` (#142331) --- .../Library/2025-12-06-13-19-43.gh-issue-142207.x_X9oH.rst | 2 ++ Modules/_remote_debugging/threads.c | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-12-06-13-19-43.gh-issue-142207.x_X9oH.rst diff --git a/Misc/NEWS.d/next/Library/2025-12-06-13-19-43.gh-issue-142207.x_X9oH.rst b/Misc/NEWS.d/next/Library/2025-12-06-13-19-43.gh-issue-142207.x_X9oH.rst new file mode 100644 index 00000000000000..69ca8c41ac9b8b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-06-13-19-43.gh-issue-142207.x_X9oH.rst @@ -0,0 +1,2 @@ +Fix: profiling.sampling may cause assertion ``!(has_gil && +gil_requested)`` diff --git a/Modules/_remote_debugging/threads.c b/Modules/_remote_debugging/threads.c index 69819eb8dcd645..774338f9dc241e 100644 --- a/Modules/_remote_debugging/threads.c +++ b/Modules/_remote_debugging/threads.c @@ -339,12 +339,10 @@ unwind_stack_for_thread( #endif if (has_gil) { status_flags |= THREAD_STATUS_HAS_GIL; + // gh-142207 for remote debugging. + gil_requested = 0; } - // Assert that we never have both HAS_GIL and GIL_REQUESTED set at the same time - // This would indicate a race condition in the GIL state tracking - assert(!(has_gil && gil_requested)); - // Check CPU status long pthread_id = GET_MEMBER(long, ts, unwinder->debug_offsets.thread_state.thread_id);