From a4709e525f5bc3a1719b33f52377cccb2af70278 Mon Sep 17 00:00:00 2001 From: Sergey Miryanov Date: Wed, 22 Oct 2025 18:14:25 +0500 Subject: [PATCH 1/4] GH-139193: Fix dump_stack when PYTHON_LLTRACE=4 (GH-139384) --- Include/internal/pycore_stackref.h | 6 ++++++ Python/ceval.c | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/Include/internal/pycore_stackref.h b/Include/internal/pycore_stackref.h index 062834368bcd29c..efe9fb3b6c7c6aa 100644 --- a/Include/internal/pycore_stackref.h +++ b/Include/internal/pycore_stackref.h @@ -296,6 +296,12 @@ PyStackRef_IsError(_PyStackRef ref) return ref.bits == Py_TAG_INVALID; } +static inline bool +PyStackRef_IsMalformed(_PyStackRef ref) +{ + return (ref.bits & Py_TAG_BITS) == Py_TAG_INVALID; +} + static inline bool PyStackRef_IsValid(_PyStackRef ref) { diff --git a/Python/ceval.c b/Python/ceval.c index f48f412fab83355..defd084db9a4bb4 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -160,6 +160,10 @@ dump_item(_PyStackRef item) printf(""); return; } + if (PyStackRef_IsMalformed(item)) { + printf(""); + return; + } if (PyStackRef_IsTaggedInt(item)) { printf("%" PRId64, (int64_t)PyStackRef_UntagInt(item)); return; From d51be28876ac0715b6fc674ef41618d214021348 Mon Sep 17 00:00:00 2001 From: Alper Date: Wed, 22 Oct 2025 08:16:28 -0700 Subject: [PATCH 2/4] gh-116738: Add critical section to dbm/gdbm context manager (gh-140391) --- Modules/_dbmmodule.c | 6 +++++- Modules/_gdbmmodule.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c index 06712015418cbcc..f88861fa24423b7 100644 --- a/Modules/_dbmmodule.c +++ b/Modules/_dbmmodule.c @@ -515,8 +515,12 @@ dbm__enter__(PyObject *self, PyObject *Py_UNUSED(dummy)) static PyObject * dbm__exit__(PyObject *self, PyObject *Py_UNUSED(args)) { + PyObject *result; dbmobject *dp = dbmobject_CAST(self); - return _dbm_dbm_close_impl(dp); + Py_BEGIN_CRITICAL_SECTION(self); + result = _dbm_dbm_close_impl(dp); + Py_END_CRITICAL_SECTION(); + return result; } static PyMethodDef dbm_methods[] = { diff --git a/Modules/_gdbmmodule.c b/Modules/_gdbmmodule.c index a6e0662ae743e9a..72f568ceb069871 100644 --- a/Modules/_gdbmmodule.c +++ b/Modules/_gdbmmodule.c @@ -690,7 +690,11 @@ gdbm__enter__(PyObject *self, PyObject *args) static PyObject * gdbm__exit__(PyObject *self, PyObject *args) { - return _gdbm_gdbm_close_impl((gdbmobject *)self); + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(self); + result = _gdbm_gdbm_close_impl((gdbmobject *)self); + Py_END_CRITICAL_SECTION(); + return result; } static PyMethodDef gdbm_methods[] = { From d2f3cfd38457204a2c47162de6f89ee3dd22fa99 Mon Sep 17 00:00:00 2001 From: Jakob Date: Wed, 22 Oct 2025 18:15:26 +0200 Subject: [PATCH 3/4] gh-140448: Default `suggest_on_error` to `True` in `argparse.ArgumentParser` (#140450) --- Doc/library/argparse.rst | 31 +++++++++---------- Doc/whatsnew/3.15.rst | 7 +++++ Lib/argparse.py | 4 +-- Lib/test/test_argparse.py | 17 +++++----- Misc/ACKS | 1 + ...-10-22-12-56-57.gh-issue-140448.GsEkXD.rst | 2 ++ 6 files changed, 36 insertions(+), 26 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-10-22-12-56-57.gh-issue-140448.GsEkXD.rst diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index a7603ac272633d3..418f514995df3a9 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -74,7 +74,7 @@ ArgumentParser objects prefix_chars='-', fromfile_prefix_chars=None, \ argument_default=None, conflict_handler='error', \ add_help=True, allow_abbrev=True, exit_on_error=True, \ - *, suggest_on_error=False, color=True) + *, suggest_on_error=True, color=True) Create a new :class:`ArgumentParser` object. All parameters should be passed as keyword arguments. Each parameter has its own more detailed description @@ -117,7 +117,7 @@ ArgumentParser objects error info when an error occurs. (default: ``True``) * suggest_on_error_ - Enables suggestions for mistyped argument choices - and subparser names (default: ``False``) + and subparser names (default: ``True``) * color_ - Allow color output (default: ``True``) @@ -134,6 +134,9 @@ ArgumentParser objects .. versionchanged:: 3.14 *suggest_on_error* and *color* parameters were added. + .. versionchanged:: 3.15 + *suggest_on_error* default changed to ``True``. + The following sections describe how each of these are used. @@ -596,13 +599,11 @@ suggest_on_error ^^^^^^^^^^^^^^^^ By default, when a user passes an invalid argument choice or subparser name, -:class:`ArgumentParser` will exit with error info and list the permissible -argument choices (if specified) or subparser names as part of the error message. - -If the user would like to enable suggestions for mistyped argument choices and -subparser names, the feature can be enabled by setting ``suggest_on_error`` to -``True``. Note that this only applies for arguments when the choices specified -are strings:: +:class:`ArgumentParser` will exit with error info and provide suggestions for +mistyped arguments. The error message will list the permissible argument +choices (if specified) or subparser names, along with a "maybe you meant" +suggestion if a close match is found. Note that this only applies for arguments +when the choices specified are strings:: >>> parser = argparse.ArgumentParser(description='Process some integers.', suggest_on_error=True) @@ -612,16 +613,14 @@ are strings:: >>> parser.parse_args(['--action', 'sumn', 1, 2, 3]) tester.py: error: argument --action: invalid choice: 'sumn', maybe you meant 'sum'? (choose from 'sum', 'max') -If you're writing code that needs to be compatible with older Python versions -and want to opportunistically use ``suggest_on_error`` when it's available, you -can set it as an attribute after initializing the parser instead of using the -keyword argument:: +You can disable suggestions by setting ``suggest_on_error`` to ``False``:: - >>> parser = argparse.ArgumentParser(description='Process some integers.') - >>> parser.suggest_on_error = True + >>> parser = argparse.ArgumentParser(description='Process some integers.', + suggest_on_error=False) .. versionadded:: 3.14 - +.. versionchanged:: 3.15 + Changed default value of ``suggest_on_error`` from ``False`` to ``True``. color ^^^^^ diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 22e9cfde06f8775..a9543bdd13e83f8 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -317,6 +317,13 @@ New modules Improved modules ================ +argparse +-------- + +* Changed the *suggest_on_error* parameter of :class:`argparse.ArgumentParser` to + default to ``True``. This enables suggestions for mistyped arguments by default. + (Contributed by Jakob Schluse in :gh:`140450`.) + calendar -------- diff --git a/Lib/argparse.py b/Lib/argparse.py index 1ddb7abbb353553..1f4413a9897eeba 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1857,7 +1857,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): - exit_on_error -- Determines whether or not ArgumentParser exits with error info when an error occurs - suggest_on_error - Enables suggestions for mistyped argument choices - and subparser names (default: ``False``) + and subparser names (default: ``True``) - color - Allow color output in help messages (default: ``False``) """ @@ -1876,7 +1876,7 @@ def __init__(self, allow_abbrev=True, exit_on_error=True, *, - suggest_on_error=False, + suggest_on_error=True, color=True, ): superinit = super(ArgumentParser, self).__init__ diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index e5d642cde662c22..d6c9c1ef2c81e88 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2287,7 +2287,7 @@ class TestArgumentAndSubparserSuggestions(TestCase): """Test error handling and suggestion when a user makes a typo""" def test_wrong_argument_error_with_suggestions(self): - parser = ErrorRaisingArgumentParser(suggest_on_error=True) + parser = ErrorRaisingArgumentParser() parser.add_argument('foo', choices=['bar', 'baz']) with self.assertRaises(ArgumentParserError) as excinfo: parser.parse_args(('bazz',)) @@ -2307,7 +2307,7 @@ def test_wrong_argument_error_no_suggestions(self): ) def test_wrong_argument_subparsers_with_suggestions(self): - parser = ErrorRaisingArgumentParser(suggest_on_error=True) + parser = ErrorRaisingArgumentParser() subparsers = parser.add_subparsers(required=True) subparsers.add_parser('foo') subparsers.add_parser('bar') @@ -2331,18 +2331,19 @@ def test_wrong_argument_subparsers_no_suggestions(self): excinfo.exception.stderr, ) - def test_wrong_argument_no_suggestion_implicit(self): - parser = ErrorRaisingArgumentParser() + def test_wrong_argument_with_suggestion_explicit(self): + parser = ErrorRaisingArgumentParser(suggest_on_error=True) parser.add_argument('foo', choices=['bar', 'baz']) with self.assertRaises(ArgumentParserError) as excinfo: parser.parse_args(('bazz',)) self.assertIn( - "error: argument foo: invalid choice: 'bazz' (choose from bar, baz)", + "error: argument foo: invalid choice: 'bazz', maybe you meant" + " 'baz'? (choose from bar, baz)", excinfo.exception.stderr, ) def test_suggestions_choices_empty(self): - parser = ErrorRaisingArgumentParser(suggest_on_error=True) + parser = ErrorRaisingArgumentParser() parser.add_argument('foo', choices=[]) with self.assertRaises(ArgumentParserError) as excinfo: parser.parse_args(('bazz',)) @@ -2352,7 +2353,7 @@ def test_suggestions_choices_empty(self): ) def test_suggestions_choices_int(self): - parser = ErrorRaisingArgumentParser(suggest_on_error=True) + parser = ErrorRaisingArgumentParser() parser.add_argument('foo', choices=[1, 2]) with self.assertRaises(ArgumentParserError) as excinfo: parser.parse_args(('3',)) @@ -2362,7 +2363,7 @@ def test_suggestions_choices_int(self): ) def test_suggestions_choices_mixed_types(self): - parser = ErrorRaisingArgumentParser(suggest_on_error=True) + parser = ErrorRaisingArgumentParser() parser.add_argument('foo', choices=[1, '2']) with self.assertRaises(ArgumentParserError) as excinfo: parser.parse_args(('3',)) diff --git a/Misc/ACKS b/Misc/ACKS index 2dc513829a2218f..6876380e0ba8d20 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1681,6 +1681,7 @@ David Scherer Wolfgang Scherer Felix Scherz Hynek Schlawack +Jakob Schluse Bob Schmertz Gregor Schmid Ralf Schmitt diff --git a/Misc/NEWS.d/next/Library/2025-10-22-12-56-57.gh-issue-140448.GsEkXD.rst b/Misc/NEWS.d/next/Library/2025-10-22-12-56-57.gh-issue-140448.GsEkXD.rst new file mode 100644 index 000000000000000..db7f92e136d41b4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-10-22-12-56-57.gh-issue-140448.GsEkXD.rst @@ -0,0 +1,2 @@ +Change the default of ``suggest_on_error`` to ``True`` in +``argparse.ArgumentParser``. From 76fea5596c235a7853cda8df87c3998d506e950c Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Wed, 22 Oct 2025 09:36:12 -0700 Subject: [PATCH 4/4] gh-130317: Fix SNaN broken tests on HP PA RISC (#140452) While looking at #140028, I found some unrelated test regressions in the 3.14 cycle. These seem to all come from #130317. From what I can tell, that made Python more correct than it was before. According to [0], HP PA RISC uses 1 for SNaN and thus a 0 for QNaN. [0]: https://grouper.ieee.org/groups/1788/email/msg03272.html --- Lib/test/test_capi/test_float.py | 5 +++++ Lib/test/test_struct.py | 12 ++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_capi/test_float.py b/Lib/test/test_capi/test_float.py index f7efe0d02549a3b..983b991b4f163d8 100644 --- a/Lib/test/test_capi/test_float.py +++ b/Lib/test/test_capi/test_float.py @@ -1,5 +1,6 @@ import math import random +import platform import sys import unittest import warnings @@ -197,6 +198,10 @@ def test_pack_unpack_roundtrip_for_nans(self): # PyFloat_Pack/Unpack*() API. See also gh-130317 and # e.g. https://developercommunity.visualstudio.com/t/155064 signaling = 0 + if platform.machine().startswith('parisc'): + # HP PA RISC uses 0 for quiet, see: + # https://en.wikipedia.org/wiki/NaN#Encoding + signaling = 1 quiet = int(not signaling) if size == 8: payload = random.randint(signaling, 0x7ffffffffffff) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index 7df01f28f09118e..75c76a36ee92f5d 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -5,6 +5,7 @@ import math import operator import unittest +import platform import struct import sys import weakref @@ -917,10 +918,17 @@ def test_half_float(self): # Check that packing produces a bit pattern representing a quiet NaN: # all exponent bits and the msb of the fraction should all be 1. + if platform.machine().startswith('parisc'): + # HP PA RISC uses 0 for quiet, see: + # https://en.wikipedia.org/wiki/NaN#Encoding + expected = 0x7c + else: + expected = 0x7e + packed = struct.pack('