From webhook-mailer at python.org Sat Apr 1 01:01:55 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sat, 01 Apr 2023 05:01:55 -0000 Subject: [Python-checkins] gh-102192: use PyErr_SetHandledException instead of the legacy PyErr_SetExcInfo (#103157) Message-ID: https://github.com/python/cpython/commit/848bdbe166b71ab2ac2c0c1d88432fb995d1444c commit: 848bdbe166b71ab2ac2c0c1d88432fb995d1444c branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-04-01T10:31:48+05:30 summary: gh-102192: use PyErr_SetHandledException instead of the legacy PyErr_SetExcInfo (#103157) files: M Python/bytecodes.c M Python/generated_cases.c.h diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 825fa705a4cd..617b6f311e2f 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1842,7 +1842,7 @@ dummy_func( ERROR_IF(match == NULL, error); if (!Py_IsNone(match)) { - PyErr_SetExcInfo(NULL, Py_NewRef(match), NULL); + PyErr_SetHandledException(match); } } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 6bb37d69cc07..7df585be0bef 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2591,7 +2591,7 @@ if (match == NULL) goto pop_2_error; if (!Py_IsNone(match)) { - PyErr_SetExcInfo(NULL, Py_NewRef(match), NULL); + PyErr_SetHandledException(match); } #line 2597 "Python/generated_cases.c.h" stack_pointer[-1] = match; From webhook-mailer at python.org Sat Apr 1 16:30:30 2023 From: webhook-mailer at python.org (iritkatriel) Date: Sat, 01 Apr 2023 20:30:30 -0000 Subject: [Python-checkins] gh-102192: deprecate _PyErr_ChainExceptions (#102935) Message-ID: https://github.com/python/cpython/commit/06249ec89fffdab25f7088c86fcbbfdcebcc3ebd commit: 06249ec89fffdab25f7088c86fcbbfdcebcc3ebd branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-04-01T21:30:23+01:00 summary: gh-102192: deprecate _PyErr_ChainExceptions (#102935) files: A Misc/NEWS.d/next/Core and Builtins/2023-03-31-12-22-25.gh-issue-102192.gYxJP_.rst M Doc/whatsnew/3.12.rst M Include/cpython/pyerrors.h diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index bd9be531fdd7..8ab96134596c 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -975,6 +975,10 @@ New Features This is less error prone and a bit more efficient. (Contributed by Mark Shannon in :gh:`101578`.) +* Add ``_PyErr_ChainExceptions1``, which takes an exception instance, + to replace the legacy-API ``_PyErr_ChainExceptions``, which is now + deprecated. (Contributed by Mark Shannon in :gh:`101578`.) + * Add :c:func:`PyException_GetArgs` and :c:func:`PyException_SetArgs` as convenience functions for retrieving and modifying the :attr:`~BaseException.args` passed to the exception's constructor. @@ -1125,6 +1129,8 @@ Deprecated * :c:func:`!PyErr_Display` is deprecated. Use :c:func:`PyErr_DisplayException` instead. (Contributed by Irit Katriel in :gh:`102755`). +* ``_PyErr_ChainExceptions`` is deprecated. Use ``_PyErr_ChainExceptions1`` + instead. (Contributed by Irit Katriel in :gh:`102192`.) Removed ------- diff --git a/Include/cpython/pyerrors.h b/Include/cpython/pyerrors.h index 65bdc942f506..758804ade2ba 100644 --- a/Include/cpython/pyerrors.h +++ b/Include/cpython/pyerrors.h @@ -98,7 +98,7 @@ PyAPI_FUNC(void) _PyErr_GetExcInfo(PyThreadState *, PyObject **, PyObject **, Py /* Context manipulation (PEP 3134) */ -PyAPI_FUNC(void) _PyErr_ChainExceptions(PyObject *, PyObject *, PyObject *); +Py_DEPRECATED(3.12) PyAPI_FUNC(void) _PyErr_ChainExceptions(PyObject *, PyObject *, PyObject *); PyAPI_FUNC(void) _PyErr_ChainExceptions1(PyObject *); /* Like PyErr_Format(), but saves current exception as __context__ and diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-31-12-22-25.gh-issue-102192.gYxJP_.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-31-12-22-25.gh-issue-102192.gYxJP_.rst new file mode 100644 index 000000000000..10dd72b1abc4 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-31-12-22-25.gh-issue-102192.gYxJP_.rst @@ -0,0 +1,2 @@ +Deprecated ``_PyErr_ChainExceptions`` in favour of +``_PyErr_ChainExceptions1``. From webhook-mailer at python.org Sun Apr 2 01:05:58 2023 From: webhook-mailer at python.org (corona10) Date: Sun, 02 Apr 2023 05:05:58 -0000 Subject: [Python-checkins] GH-102456: Fix docstring and getopt options for base64 (gh-102457) Message-ID: https://github.com/python/cpython/commit/d828b35785eeb590b8ca92684038f33177989e46 commit: d828b35785eeb590b8ca92684038f33177989e46 branch: main author: Partha P. Mukherjee committer: corona10 date: 2023-04-02T14:05:50+09:00 summary: GH-102456: Fix docstring and getopt options for base64 (gh-102457) files: M Lib/base64.py diff --git a/Lib/base64.py b/Lib/base64.py index 95dc7b008605..e233647ee766 100755 --- a/Lib/base64.py +++ b/Lib/base64.py @@ -558,12 +558,12 @@ def decodebytes(s): def main(): """Small main program""" import sys, getopt - usage = f"""usage: {sys.argv[0]} [-h|-d|-e|-u|-t] [file|-] + usage = f"""usage: {sys.argv[0]} [-h|-d|-e|-u] [file|-] -h: print this help message and exit -d, -u: decode -e: encode (default)""" try: - opts, args = getopt.getopt(sys.argv[1:], 'hdeut') + opts, args = getopt.getopt(sys.argv[1:], 'hdeu') except getopt.error as msg: sys.stdout = sys.stderr print(msg) From webhook-mailer at python.org Sun Apr 2 09:22:27 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sun, 02 Apr 2023 13:22:27 -0000 Subject: [Python-checkins] gh-102433: Use `inspect.getattr_static` in `typing._ProtocolMeta.__instancecheck__` (#103034) Message-ID: https://github.com/python/cpython/commit/6d59c9e32ebb6d8468c7eb26e7cf3efd458c7a73 commit: 6d59c9e32ebb6d8468c7eb26e7cf3efd458c7a73 branch: main author: Alex Waygood committer: AlexWaygood date: 2023-04-02T14:22:19+01:00 summary: gh-102433: Use `inspect.getattr_static` in `typing._ProtocolMeta.__instancecheck__` (#103034) files: A Misc/NEWS.d/next/Library/2023-03-25-16-57-18.gh-issue-102433.L-7x2Q.rst M Doc/library/typing.rst M Doc/whatsnew/3.12.rst M Lib/test/test_typing.py M Lib/typing.py diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 384458d3aa66..8728ca7b6b35 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1598,6 +1598,15 @@ These are not used in annotations. They are building blocks for creating generic import threading assert isinstance(threading.Thread(name='Bob'), Named) + .. versionchanged:: 3.12 + The internal implementation of :func:`isinstance` checks against + runtime-checkable protocols now uses :func:`inspect.getattr_static` + to look up attributes (previously, :func:`hasattr` was used). + As a result, some objects which used to be considered instances + of a runtime-checkable protocol may no longer be considered instances + of that protocol on Python 3.12+, and vice versa. + Most users are unlikely to be affected by this change. + .. note:: :func:`!runtime_checkable` will check only the presence of the required diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 8ab96134596c..93543cb0790f 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -391,6 +391,17 @@ typing same name on a base class, as per :pep:`698`. (Contributed by Steven Troxler in :gh:`101564`.) +* :func:`isinstance` checks against + :func:`runtime-checkable protocols ` now use + :func:`inspect.getattr_static` rather than :func:`hasattr` to lookup whether + attributes exist. This means that descriptors and :meth:`~object.__getattr__` + methods are no longer unexpectedly evaluated during ``isinstance()`` checks + against runtime-checkable protocols. However, it may also mean that some + objects which used to be considered instances of a runtime-checkable protocol + may no longer be considered instances of that protocol on Python 3.12+, and + vice versa. Most users are unlikely to be affected by this change. + (Contributed by Alex Waygood in :gh:`102433`.) + sys --- diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 23bf2b5e183a..7d2e6a6a9f62 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2637,7 +2637,15 @@ def attr(self): ... class PG1(Protocol[T]): attr: T - for protocol_class in P, P1, PG, PG1: + @runtime_checkable + class MethodP(Protocol): + def attr(self): ... + + @runtime_checkable + class MethodPG(Protocol[T]): + def attr(self) -> T: ... + + for protocol_class in P, P1, PG, PG1, MethodP, MethodPG: for klass in C, D, E, F: with self.subTest( klass=klass.__name__, @@ -2662,7 +2670,12 @@ def attr(self): ... class BadPG1(Protocol[T]): attr: T - for obj in PG[T], PG[C], PG1[T], PG1[C], BadP, BadP1, BadPG, BadPG1: + cases = ( + PG[T], PG[C], PG1[T], PG1[C], MethodPG[T], + MethodPG[C], BadP, BadP1, BadPG, BadPG1 + ) + + for obj in cases: for klass in C, D, E, F, Empty: with self.subTest(klass=klass.__name__, obj=obj): with self.assertRaises(TypeError): @@ -2685,6 +2698,82 @@ def __dir__(self): self.assertIsInstance(CustomDirWithX(), HasX) self.assertNotIsInstance(CustomDirWithoutX(), HasX) + def test_protocols_isinstance_attribute_access_with_side_effects(self): + class C: + @property + def attr(self): + raise AttributeError('no') + + class CustomDescriptor: + def __get__(self, obj, objtype=None): + raise RuntimeError("NO") + + class D: + attr = CustomDescriptor() + + # Check that properties set on superclasses + # are still found by the isinstance() logic + class E(C): ... + class F(D): ... + + class WhyWouldYouDoThis: + def __getattr__(self, name): + raise RuntimeError("wut") + + T = TypeVar('T') + + @runtime_checkable + class P(Protocol): + @property + def attr(self): ... + + @runtime_checkable + class P1(Protocol): + attr: int + + @runtime_checkable + class PG(Protocol[T]): + @property + def attr(self): ... + + @runtime_checkable + class PG1(Protocol[T]): + attr: T + + @runtime_checkable + class MethodP(Protocol): + def attr(self): ... + + @runtime_checkable + class MethodPG(Protocol[T]): + def attr(self) -> T: ... + + for protocol_class in P, P1, PG, PG1, MethodP, MethodPG: + for klass in C, D, E, F: + with self.subTest( + klass=klass.__name__, + protocol_class=protocol_class.__name__ + ): + self.assertIsInstance(klass(), protocol_class) + + with self.subTest( + klass="WhyWouldYouDoThis", + protocol_class=protocol_class.__name__ + ): + self.assertNotIsInstance(WhyWouldYouDoThis(), protocol_class) + + def test_protocols_isinstance___slots__(self): + # As per the consensus in https://github.com/python/typing/issues/1367, + # this is desirable behaviour + @runtime_checkable + class HasX(Protocol): + x: int + + class HasNothingButSlots: + __slots__ = ("x",) + + self.assertIsInstance(HasNothingButSlots(), HasX) + def test_protocols_isinstance_py36(self): class APoint: def __init__(self, x, y, label): diff --git a/Lib/typing.py b/Lib/typing.py index a88542cfbaec..442d684d14c9 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1998,6 +1998,17 @@ def _allow_reckless_class_checks(depth=3): } + at functools.cache +def _lazy_load_getattr_static(): + # Import getattr_static lazily so as not to slow down the import of typing.py + # Cache the result so we don't slow down _ProtocolMeta.__instancecheck__ unnecessarily + from inspect import getattr_static + return getattr_static + + +_cleanups.append(_lazy_load_getattr_static.cache_clear) + + class _ProtocolMeta(ABCMeta): # This metaclass is really unfortunate and exists only because of # the lack of __instancehook__. @@ -2025,12 +2036,17 @@ def __instancecheck__(cls, instance): return True if is_protocol_cls: - if all(hasattr(instance, attr) and - # All *methods* can be blocked by setting them to None. - (not callable(getattr(cls, attr, None)) or - getattr(instance, attr) is not None) - for attr in protocol_attrs): + getattr_static = _lazy_load_getattr_static() + for attr in protocol_attrs: + try: + val = getattr_static(instance, attr) + except AttributeError: + break + if callable(getattr(cls, attr, None)) and val is None: + break + else: return True + return super().__instancecheck__(instance) diff --git a/Misc/NEWS.d/next/Library/2023-03-25-16-57-18.gh-issue-102433.L-7x2Q.rst b/Misc/NEWS.d/next/Library/2023-03-25-16-57-18.gh-issue-102433.L-7x2Q.rst new file mode 100644 index 000000000000..a4de4b4448f3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-25-16-57-18.gh-issue-102433.L-7x2Q.rst @@ -0,0 +1,10 @@ +:func:`isinstance` checks against :func:`runtime-checkable protocols +` now use :func:`inspect.getattr_static` rather +than :func:`hasattr` to lookup whether attributes exist. This means that +descriptors and :meth:`~object.__getattr__` methods are no longer +unexpectedly evaluated during ``isinstance()`` checks against +runtime-checkable protocols. However, it may also mean that some objects +which used to be considered instances of a runtime-checkable protocol may no +longer be considered instances of that protocol on Python 3.12+, and vice +versa. Most users are unlikely to be affected by this change. Patch by Alex +Waygood. From webhook-mailer at python.org Sun Apr 2 11:25:59 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 02 Apr 2023 15:25:59 -0000 Subject: [Python-checkins] fix typo in _ssl.c (GH-103192) Message-ID: https://github.com/python/cpython/commit/a0305c5fdfdef7a362d0262c54399c4a6013d1ea commit: a0305c5fdfdef7a362d0262c54399c4a6013d1ea branch: main author: Ikko Eltociear Ashimine committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-02T08:25:46-07:00 summary: fix typo in _ssl.c (GH-103192) seperated -> separated Automerge-Triggered-By: GH:AlexWaygood files: M Modules/_ssl.c diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 3fbb37332f67..e0351a89e6a1 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2006,7 +2006,7 @@ _ssl__SSLSocket_shared_ciphers_impl(PySSLSocket *self) /* Rather than use SSL_get_shared_ciphers, we use an equivalent algorithm because: - 1) It returns a colon seperated list of strings, in an undefined + 1) It returns a colon separated list of strings, in an undefined order, that we would have to post process back into tuples. 2) It will return a truncated string with no indication that it has done so, if the buffer is too small. From webhook-mailer at python.org Sun Apr 2 18:12:58 2023 From: webhook-mailer at python.org (giampaolo) Date: Sun, 02 Apr 2023 22:12:58 -0000 Subject: [Python-checkins] bpo-4080: unittest durations (#12271) Message-ID: https://github.com/python/cpython/commit/6883007a86bdf0d7cf4560b949fd5e577dab1013 commit: 6883007a86bdf0d7cf4560b949fd5e577dab1013 branch: main author: Giampaolo Rodola committer: giampaolo date: 2023-04-03T00:12:51+02:00 summary: bpo-4080: unittest durations (#12271) files: A Misc/NEWS.d/next/Library/2022-11-24-13-23-07.gh-issue-48330.6uAX9F.rst M Doc/library/unittest.rst M Doc/whatsnew/3.12.rst M Lib/test/test_unittest/support.py M Lib/test/test_unittest/test_break.py M Lib/test/test_unittest/test_program.py M Lib/test/test_unittest/test_result.py M Lib/test/test_unittest/test_runner.py M Lib/unittest/case.py M Lib/unittest/main.py M Lib/unittest/result.py M Lib/unittest/runner.py diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index 1577149e9764..d1a977fd7da6 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -244,6 +244,10 @@ Command-line options Show local variables in tracebacks. +.. cmdoption:: --durations N + + Show the N slowest test cases (N=0 for all). + .. versionadded:: 3.2 The command-line options ``-b``, ``-c`` and ``-f`` were added. @@ -253,10 +257,12 @@ Command-line options .. versionadded:: 3.7 The command-line option ``-k``. +.. versionadded:: 3.12 + The command-line option ``--durations``. + The command line can also be used for test discovery, for running all of the tests in a project or just a subset. - .. _unittest-test-discovery: Test Discovery @@ -2009,6 +2015,13 @@ Loading and running tests A list containing :class:`TestCase` instances that were marked as expected failures, but succeeded. + .. attribute:: collectedDurations + + A list containing 2-tuples of :class:`TestCase` instances and floats + representing the elapsed time of each test which was run. + + .. versionadded:: 3.12 + .. attribute:: shouldStop Set to ``True`` when the execution of tests should stop by :meth:`stop`. @@ -2160,14 +2173,27 @@ Loading and running tests .. versionadded:: 3.4 + .. method:: addDuration(test, elapsed) + + Called when the test case finishes. *elapsed* is the time represented in + seconds, and it includes the execution of cleanup functions. + + .. versionadded:: 3.12 -.. class:: TextTestResult(stream, descriptions, verbosity) +.. class:: TextTestResult(stream, descriptions, verbosity, *, durations=None) A concrete implementation of :class:`TestResult` used by the - :class:`TextTestRunner`. + :class:`TextTestRunner`. Subclasses should accept ``**kwargs`` to ensure + compatibility as the interface changes. .. versionadded:: 3.2 + .. versionadded:: 3.12 + Added *durations* keyword argument. + + .. versionchanged:: 3.12 + Subclasses should accept ``**kwargs`` to ensure compatibility as the + interface changes. .. data:: defaultTestLoader @@ -2177,7 +2203,8 @@ Loading and running tests .. class:: TextTestRunner(stream=None, descriptions=True, verbosity=1, failfast=False, \ - buffer=False, resultclass=None, warnings=None, *, tb_locals=False) + buffer=False, resultclass=None, warnings=None, *, \ + tb_locals=False, durations=None) A basic test runner implementation that outputs results to a stream. If *stream* is ``None``, the default, :data:`sys.stderr` is used as the output stream. This class @@ -2195,14 +2222,17 @@ Loading and running tests *warnings* to ``None``. .. versionchanged:: 3.2 - Added the ``warnings`` argument. + Added the *warnings* parameter. .. versionchanged:: 3.2 The default stream is set to :data:`sys.stderr` at instantiation time rather than import time. .. versionchanged:: 3.5 - Added the tb_locals parameter. + Added the *tb_locals* parameter. + + .. versionchanged:: 3.12 + Added the *durations* parameter. .. method:: _makeResult() diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 93543cb0790f..3df3ef711a90 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -371,6 +371,27 @@ unicodedata * The Unicode database has been updated to version 15.0.0. (Contributed by Benjamin Peterson in :gh:`96734`). +unittest +-------- + +Added ``--durations`` command line option, showing the N slowest test cases:: + + python3 -m unittest --durations=3 lib.tests.test_threading + ..... + Slowest test durations + ---------------------------------------------------------------------- + 1.210s test_timeout (Lib.test.test_threading.BarrierTests) + 1.003s test_default_timeout (Lib.test.test_threading.BarrierTests) + 0.518s test_timeout (Lib.test.test_threading.EventTests) + + (0.000 durations hidden. Use -v to show these durations.) + ---------------------------------------------------------------------- + Ran 158 tests in 9.869s + + OK (skipped=3) + +(Contributed by Giampaolo Rodola in :issue:`4080`) + uuid ---- diff --git a/Lib/test/test_unittest/support.py b/Lib/test/test_unittest/support.py index 529265304f28..8c97bf5c7297 100644 --- a/Lib/test/test_unittest/support.py +++ b/Lib/test/test_unittest/support.py @@ -136,3 +136,19 @@ def addSuccess(self, test): def wasSuccessful(self): return True + + +class BufferedWriter: + def __init__(self): + self.result = '' + self.buffer = '' + + def write(self, arg): + self.buffer += arg + + def flush(self): + self.result += self.buffer + self.buffer = '' + + def getvalue(self): + return self.result diff --git a/Lib/test/test_unittest/test_break.py b/Lib/test/test_unittest/test_break.py index 33cbdd2661c1..1da98af3e74d 100644 --- a/Lib/test/test_unittest/test_break.py +++ b/Lib/test/test_unittest/test_break.py @@ -236,6 +236,7 @@ def __init__(self, catchbreak): self.testRunner = FakeRunner self.test = test self.result = None + self.durations = None p = Program(False) p.runTests() @@ -244,7 +245,8 @@ def __init__(self, catchbreak): 'verbosity': verbosity, 'failfast': failfast, 'tb_locals': False, - 'warnings': None})]) + 'warnings': None, + 'durations': None})]) self.assertEqual(FakeRunner.runArgs, [test]) self.assertEqual(p.result, result) @@ -259,7 +261,8 @@ def __init__(self, catchbreak): 'verbosity': verbosity, 'failfast': failfast, 'tb_locals': False, - 'warnings': None})]) + 'warnings': None, + 'durations': None})]) self.assertEqual(FakeRunner.runArgs, [test]) self.assertEqual(p.result, result) diff --git a/Lib/test/test_unittest/test_program.py b/Lib/test/test_unittest/test_program.py index 3645bcf4b435..f138f6836514 100644 --- a/Lib/test/test_unittest/test_program.py +++ b/Lib/test/test_unittest/test_program.py @@ -284,6 +284,7 @@ def testRunTestsRunnerClass(self): program.failfast = 'failfast' program.buffer = 'buffer' program.warnings = 'warnings' + program.durations = '5' program.runTests() @@ -291,7 +292,8 @@ def testRunTestsRunnerClass(self): 'failfast': 'failfast', 'buffer': 'buffer', 'tb_locals': False, - 'warnings': 'warnings'}) + 'warnings': 'warnings', + 'durations': '5'}) self.assertEqual(FakeRunner.test, 'test') self.assertIs(program.result, RESULT) @@ -320,7 +322,8 @@ def test_locals(self): 'failfast': False, 'tb_locals': True, 'verbosity': 1, - 'warnings': None}) + 'warnings': None, + 'durations': None}) def testRunTestsOldRunnerClass(self): program = self.program @@ -333,6 +336,7 @@ def testRunTestsOldRunnerClass(self): program.failfast = 'failfast' program.buffer = 'buffer' program.test = 'test' + program.durations = '0' program.runTests() @@ -356,6 +360,7 @@ def fakeInstallHandler(): program = self.program program.catchbreak = True + program.durations = None program.testRunner = FakeRunner diff --git a/Lib/test/test_unittest/test_result.py b/Lib/test/test_unittest/test_result.py index efd9c9023505..37d0fe12409e 100644 --- a/Lib/test/test_unittest/test_result.py +++ b/Lib/test/test_unittest/test_result.py @@ -6,7 +6,9 @@ import traceback import unittest +from unittest import mock from unittest.util import strclass +from test.test_unittest.support import BufferedWriter class MockTraceback(object): @@ -33,22 +35,6 @@ def bad_cleanup2(): raise ValueError('bad cleanup2') -class BufferedWriter: - def __init__(self): - self.result = '' - self.buffer = '' - - def write(self, arg): - self.buffer += arg - - def flush(self): - self.result += self.buffer - self.buffer = '' - - def getvalue(self): - return self.result - - class Test_TestResult(unittest.TestCase): # Note: there are not separate tests for TestResult.wasSuccessful(), # TestResult.errors, TestResult.failures, TestResult.testsRun or diff --git a/Lib/test/test_unittest/test_runner.py b/Lib/test/test_unittest/test_runner.py index df584b7620d0..1ce42a106c58 100644 --- a/Lib/test/test_unittest/test_runner.py +++ b/Lib/test/test_unittest/test_runner.py @@ -8,8 +8,11 @@ import unittest from unittest.case import _Outcome -from test.test_unittest.support import (LoggingResult, - ResultWithNoStartTestRunStopTestRun) +from test.test_unittest.support import ( + BufferedWriter, + LoggingResult, + ResultWithNoStartTestRunStopTestRun, +) def resultFactory(*_): @@ -1176,6 +1179,7 @@ def test_init(self): self.assertTrue(runner.descriptions) self.assertEqual(runner.resultclass, unittest.TextTestResult) self.assertFalse(runner.tb_locals) + self.assertIsNone(runner.durations) def test_multiple_inheritance(self): class AResult(unittest.TestResult): @@ -1362,6 +1366,65 @@ def testSpecifiedStreamUsed(self): runner = unittest.TextTestRunner(f) self.assertTrue(runner.stream.stream is f) + def test_durations(self): + def run(test, expect_durations): + stream = BufferedWriter() + runner = unittest.TextTestRunner(stream=stream, durations=5, verbosity=2) + result = runner.run(test) + self.assertEqual(result.durations, 5) + stream.flush() + text = stream.getvalue() + regex = r"\n\d+.\d\d\ds" + if expect_durations: + self.assertEqual(len(result.collectedDurations), 1) + self.assertIn('Slowest test durations', text) + self.assertRegex(text, regex) + else: + self.assertEqual(len(result.collectedDurations), 0) + self.assertNotIn('Slowest test durations', text) + self.assertNotRegex(text, regex) + + # success + class Foo(unittest.TestCase): + def test_1(self): + pass + + run(Foo('test_1'), True) + + # failure + class Foo(unittest.TestCase): + def test_1(self): + self.assertEqual(0, 1) + + run(Foo('test_1'), True) + + # error + class Foo(unittest.TestCase): + def test_1(self): + 1 / 0 + + run(Foo('test_1'), True) + + + # error in setUp and tearDown + class Foo(unittest.TestCase): + def setUp(self): + 1 / 0 + tearDown = setUp + def test_1(self): + pass + + run(Foo('test_1'), True) + + # skip (expect no durations) + class Foo(unittest.TestCase): + @unittest.skip("reason") + def test_1(self): + pass + + run(Foo('test_1'), False) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py index 5167c5f843f0..018f22e7ce0c 100644 --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -9,6 +9,7 @@ import collections import contextlib import traceback +import time import types from . import result @@ -572,6 +573,15 @@ def _addUnexpectedSuccess(self, result): else: addUnexpectedSuccess(self) + def _addDuration(self, result, elapsed): + try: + addDuration = result.addDuration + except AttributeError: + warnings.warn("TestResult has no addDuration method", + RuntimeWarning) + else: + addDuration(self, elapsed) + def _callSetUp(self): self.setUp() @@ -612,6 +622,7 @@ def run(self, result=None): getattr(testMethod, "__unittest_expecting_failure__", False) ) outcome = _Outcome(result) + start_time = time.perf_counter() try: self._outcome = outcome @@ -625,6 +636,7 @@ def run(self, result=None): with outcome.testPartExecutor(self): self._callTearDown() self.doCleanups() + self._addDuration(result, (time.perf_counter() - start_time)) if outcome.success: if expecting_failure: diff --git a/Lib/unittest/main.py b/Lib/unittest/main.py index 046fbd3a45dc..0792750ffd9e 100644 --- a/Lib/unittest/main.py +++ b/Lib/unittest/main.py @@ -66,7 +66,8 @@ class TestProgram(object): def __init__(self, module='__main__', defaultTest=None, argv=None, testRunner=None, testLoader=loader.defaultTestLoader, exit=True, verbosity=1, failfast=None, catchbreak=None, - buffer=None, warnings=None, *, tb_locals=False): + buffer=None, warnings=None, *, tb_locals=False, + durations=None): if isinstance(module, str): self.module = __import__(module) for part in module.split('.')[1:]: @@ -82,6 +83,7 @@ def __init__(self, module='__main__', defaultTest=None, argv=None, self.verbosity = verbosity self.buffer = buffer self.tb_locals = tb_locals + self.durations = durations if warnings is None and not sys.warnoptions: # even if DeprecationWarnings are ignored by default # print them anyway unless other warnings settings are @@ -178,6 +180,9 @@ def _getParentArgParser(self): parser.add_argument('--locals', dest='tb_locals', action='store_true', help='Show local variables in tracebacks') + parser.add_argument('--durations', dest='durations', type=int, + default=None, metavar="N", + help='Show the N slowest test cases (N=0 for all)') if self.failfast is None: parser.add_argument('-f', '--failfast', dest='failfast', action='store_true', @@ -258,9 +263,10 @@ def runTests(self): failfast=self.failfast, buffer=self.buffer, warnings=self.warnings, - tb_locals=self.tb_locals) + tb_locals=self.tb_locals, + durations=self.durations) except TypeError: - # didn't accept the tb_locals argument + # didn't accept the tb_locals or durations argument testRunner = self.testRunner(verbosity=self.verbosity, failfast=self.failfast, buffer=self.buffer, diff --git a/Lib/unittest/result.py b/Lib/unittest/result.py index 5ca4c23238b4..fa9bea47c888 100644 --- a/Lib/unittest/result.py +++ b/Lib/unittest/result.py @@ -43,6 +43,7 @@ def __init__(self, stream=None, descriptions=None, verbosity=None): self.skipped = [] self.expectedFailures = [] self.unexpectedSuccesses = [] + self.collectedDurations = [] self.shouldStop = False self.buffer = False self.tb_locals = False @@ -157,6 +158,12 @@ def addUnexpectedSuccess(self, test): """Called when a test was expected to fail, but succeed.""" self.unexpectedSuccesses.append(test) + def addDuration(self, test, elapsed): + """Called when a test finished to run, regardless of its outcome.""" + # support for a TextTestRunner using an old TestResult class + if hasattr(self, "collectedDurations"): + self.collectedDurations.append((test, elapsed)) + def wasSuccessful(self): """Tells whether or not this result was a success.""" # The hasattr check is for test_result's OldResult test. That diff --git a/Lib/unittest/runner.py b/Lib/unittest/runner.py index 6678adb6a7d8..a51c5c562df0 100644 --- a/Lib/unittest/runner.py +++ b/Lib/unittest/runner.py @@ -35,13 +35,16 @@ class TextTestResult(result.TestResult): separator1 = '=' * 70 separator2 = '-' * 70 - def __init__(self, stream, descriptions, verbosity): + def __init__(self, stream, descriptions, verbosity, *, durations=None): + """Construct a TextTestResult. Subclasses should accept **kwargs + to ensure compatibility as the interface changes.""" super(TextTestResult, self).__init__(stream, descriptions, verbosity) self.stream = stream self.showAll = verbosity > 1 self.dots = verbosity == 1 self.descriptions = descriptions self._newline = True + self.durations = durations def getDescription(self, test): doc_first_line = test.shortDescription() @@ -168,7 +171,7 @@ class TextTestRunner(object): def __init__(self, stream=None, descriptions=True, verbosity=1, failfast=False, buffer=False, resultclass=None, warnings=None, - *, tb_locals=False): + *, tb_locals=False, durations=None): """Construct a TextTestRunner. Subclasses should accept **kwargs to ensure compatibility as the @@ -182,12 +185,41 @@ def __init__(self, stream=None, descriptions=True, verbosity=1, self.failfast = failfast self.buffer = buffer self.tb_locals = tb_locals + self.durations = durations self.warnings = warnings if resultclass is not None: self.resultclass = resultclass def _makeResult(self): - return self.resultclass(self.stream, self.descriptions, self.verbosity) + try: + return self.resultclass(self.stream, self.descriptions, + self.verbosity, durations=self.durations) + except TypeError: + # didn't accept the durations argument + return self.resultclass(self.stream, self.descriptions, + self.verbosity) + + def _printDurations(self, result): + if not result.collectedDurations: + return + ls = sorted(result.collectedDurations, key=lambda x: x[1], + reverse=True) + if self.durations > 0: + ls = ls[:self.durations] + self.stream.writeln("Slowest test durations") + if hasattr(result, 'separator2'): + self.stream.writeln(result.separator2) + hidden = False + for test, elapsed in ls: + if self.verbosity < 2 and elapsed < 0.001: + hidden = True + continue + self.stream.writeln("%-10s %s" % ("%.3fs" % elapsed, test)) + if hidden: + self.stream.writeln("\n(durations < 0.001s were hidden; " + "use -v to show these durations)") + else: + self.stream.writeln("") def run(self, test): "Run the given test case or test suite." @@ -213,8 +245,12 @@ def run(self, test): stopTime = time.perf_counter() timeTaken = stopTime - startTime result.printErrors() + if self.durations is not None: + self._printDurations(result) + if hasattr(result, 'separator2'): self.stream.writeln(result.separator2) + run = result.testsRun self.stream.writeln("Ran %d test%s in %.3fs" % (run, run != 1 and "s" or "", timeTaken)) diff --git a/Misc/NEWS.d/next/Library/2022-11-24-13-23-07.gh-issue-48330.6uAX9F.rst b/Misc/NEWS.d/next/Library/2022-11-24-13-23-07.gh-issue-48330.6uAX9F.rst new file mode 100644 index 000000000000..5b63a0a6b96d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-11-24-13-23-07.gh-issue-48330.6uAX9F.rst @@ -0,0 +1,8 @@ +Added ``--durations`` command line option, showing the N slowest test cases. +:class:`unittest.TextTestRunner` and :class:`unittest.TextTestResult` +constructors accept a new *durations* keyword argument. Subclasses should take +this into account or accept ``**kwargs``. Added +:meth:`unittest.TestResult.addDuration` method and +:attr:`unittest.TestResult.collectedDurations` attribute. + +(Contributed by Giampaolo Rodola) From webhook-mailer at python.org Sun Apr 2 18:18:32 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Sun, 02 Apr 2023 22:18:32 -0000 Subject: [Python-checkins] gh-103109: Document ignore_warnings() test support helper (#103110) Message-ID: https://github.com/python/cpython/commit/32937d6aa414ec7db5c63ef277f21db1880b3af4 commit: 32937d6aa414ec7db5c63ef277f21db1880b3af4 branch: main author: Charlie Zhao committer: erlend-aasland date: 2023-04-03T00:18:25+02:00 summary: gh-103109: Document ignore_warnings() test support helper (#103110) Co-authored-by: C.A.M. Gerlach files: M Doc/library/test.rst M Lib/test/support/warnings_helper.py diff --git a/Doc/library/test.rst b/Doc/library/test.rst index c60b4da75d1a..20f633b8f569 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -1691,6 +1691,21 @@ The :mod:`test.support.warnings_helper` module provides support for warnings tes .. versionadded:: 3.10 +.. function:: ignore_warnings(*, category) + + Suppress warnings that are instances of *category*, + which must be :exc:`Warning` or a subclass. + Roughly equivalent to :func:`warnings.catch_warnings` + with :meth:`warnings.simplefilter('ignore', category=category) `. + For example:: + + @warning_helper.ignore_warnings(category=DeprecationWarning) + def test_suppress_warning(): + # do something + + .. versionadded:: 3.8 + + .. function:: check_no_resource_warning(testcase) Context manager to check that no :exc:`ResourceWarning` was raised. You diff --git a/Lib/test/support/warnings_helper.py b/Lib/test/support/warnings_helper.py index 28e96f88b244..c1bf05623006 100644 --- a/Lib/test/support/warnings_helper.py +++ b/Lib/test/support/warnings_helper.py @@ -44,7 +44,7 @@ def check_syntax_warning(testcase, statement, errtext='', def ignore_warnings(*, category): - """Decorator to suppress deprecation warnings. + """Decorator to suppress warnings. Use of context managers to hide warnings make diffs more noisy and tools like 'git blame' less useful. From webhook-mailer at python.org Sun Apr 2 18:39:05 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 02 Apr 2023 22:39:05 -0000 Subject: [Python-checkins] gh-103109: Document ignore_warnings() test support helper (GH-103110) Message-ID: https://github.com/python/cpython/commit/9a8ce957482e0d811be6ec2987e99a1f4be3558a commit: 9a8ce957482e0d811be6ec2987e99a1f4be3558a branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-02T15:38:58-07:00 summary: gh-103109: Document ignore_warnings() test support helper (GH-103110) (cherry picked from commit 32937d6aa414ec7db5c63ef277f21db1880b3af4) Co-authored-by: Charlie Zhao Co-authored-by: C.A.M. Gerlach files: M Doc/library/test.rst M Lib/test/support/warnings_helper.py diff --git a/Doc/library/test.rst b/Doc/library/test.rst index 922a8f0b512f..700d3961a423 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -1622,6 +1622,21 @@ The :mod:`test.support.warnings_helper` module provides support for warnings tes .. versionadded:: 3.10 +.. function:: ignore_warnings(*, category) + + Suppress warnings that are instances of *category*, + which must be :exc:`Warning` or a subclass. + Roughly equivalent to :func:`warnings.catch_warnings` + with :meth:`warnings.simplefilter('ignore', category=category) `. + For example:: + + @warning_helper.ignore_warnings(category=DeprecationWarning) + def test_suppress_warning(): + # do something + + .. versionadded:: 3.8 + + .. function:: check_no_resource_warning(testcase) Context manager to check that no :exc:`ResourceWarning` was raised. You diff --git a/Lib/test/support/warnings_helper.py b/Lib/test/support/warnings_helper.py index a024fbe5beaa..93a91e6d99f9 100644 --- a/Lib/test/support/warnings_helper.py +++ b/Lib/test/support/warnings_helper.py @@ -36,7 +36,7 @@ def check_syntax_warning(testcase, statement, errtext='', def ignore_warnings(*, category): - """Decorator to suppress deprecation warnings. + """Decorator to suppress warnings. Use of context managers to hide warnings make diffs more noisy and tools like 'git blame' less useful. From webhook-mailer at python.org Sun Apr 2 18:42:50 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 02 Apr 2023 22:42:50 -0000 Subject: [Python-checkins] gh-103109: Document ignore_warnings() test support helper (GH-103110) Message-ID: https://github.com/python/cpython/commit/0854bdf15f93f0a4bad44dc3955b713c721c394f commit: 0854bdf15f93f0a4bad44dc3955b713c721c394f branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-02T15:42:43-07:00 summary: gh-103109: Document ignore_warnings() test support helper (GH-103110) (cherry picked from commit 32937d6aa414ec7db5c63ef277f21db1880b3af4) Co-authored-by: Charlie Zhao Co-authored-by: C.A.M. Gerlach files: M Doc/library/test.rst M Lib/test/support/warnings_helper.py diff --git a/Doc/library/test.rst b/Doc/library/test.rst index 8e05ff39c109..0bddd31ae259 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -1631,6 +1631,21 @@ The :mod:`test.support.warnings_helper` module provides support for warnings tes .. versionadded:: 3.10 +.. function:: ignore_warnings(*, category) + + Suppress warnings that are instances of *category*, + which must be :exc:`Warning` or a subclass. + Roughly equivalent to :func:`warnings.catch_warnings` + with :meth:`warnings.simplefilter('ignore', category=category) `. + For example:: + + @warning_helper.ignore_warnings(category=DeprecationWarning) + def test_suppress_warning(): + # do something + + .. versionadded:: 3.8 + + .. function:: check_no_resource_warning(testcase) Context manager to check that no :exc:`ResourceWarning` was raised. You diff --git a/Lib/test/support/warnings_helper.py b/Lib/test/support/warnings_helper.py index 28e96f88b244..c1bf05623006 100644 --- a/Lib/test/support/warnings_helper.py +++ b/Lib/test/support/warnings_helper.py @@ -44,7 +44,7 @@ def check_syntax_warning(testcase, statement, errtext='', def ignore_warnings(*, category): - """Decorator to suppress deprecation warnings. + """Decorator to suppress warnings. Use of context managers to hide warnings make diffs more noisy and tools like 'git blame' less useful. From webhook-mailer at python.org Sun Apr 2 18:44:23 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Sun, 02 Apr 2023 22:44:23 -0000 Subject: [Python-checkins] gh-102994: Profile docs has typo in example (#103074) Message-ID: https://github.com/python/cpython/commit/55decb72c4d2e4ea00ed13da5dd0fd22cecb9083 commit: 55decb72c4d2e4ea00ed13da5dd0fd22cecb9083 branch: main author: Nouran Ali committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-04-02T15:44:16-07:00 summary: gh-102994: Profile docs has typo in example (#103074) files: M Doc/library/profile.rst diff --git a/Doc/library/profile.rst b/Doc/library/profile.rst index c2189e02656c..723f927135a0 100644 --- a/Doc/library/profile.rst +++ b/Doc/library/profile.rst @@ -82,7 +82,7 @@ the following:: The first line indicates that 214 calls were monitored. Of those calls, 207 were :dfn:`primitive`, meaning that the call was not induced via recursion. The -next line: ``Ordered by: cumulative name``, indicates that the text string in the +next line: ``Ordered by: cumulative time``, indicates that the text string in the far right column was used to sort the output. The column headings include: ncalls From webhook-mailer at python.org Sun Apr 2 18:47:38 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Sun, 02 Apr 2023 22:47:38 -0000 Subject: [Python-checkins] gh-102038: Skip a sometimes unnecessary stat in site.py (#102039) Message-ID: https://github.com/python/cpython/commit/385b5d6e091da454c3e0d3f7271acf3af26d8532 commit: 385b5d6e091da454c3e0d3f7271acf3af26d8532 branch: main author: Shantanu <12621235+hauntsaninja at users.noreply.github.com> committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-04-02T15:47:31-07:00 summary: gh-102038: Skip a sometimes unnecessary stat in site.py (#102039) files: A Misc/NEWS.d/next/Library/2023-02-19-01-49-46.gh-issue-102038.n3if3D.rst M Lib/site.py diff --git a/Lib/site.py b/Lib/site.py index 5c1ff31f4e0f..672fa7b000ad 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -492,20 +492,23 @@ def venv(known_paths): executable = sys._base_executable = os.environ['__PYVENV_LAUNCHER__'] else: executable = sys.executable - exe_dir, _ = os.path.split(os.path.abspath(executable)) + exe_dir = os.path.dirname(os.path.abspath(executable)) site_prefix = os.path.dirname(exe_dir) sys._home = None conf_basename = 'pyvenv.cfg' - candidate_confs = [ - conffile for conffile in ( - os.path.join(exe_dir, conf_basename), - os.path.join(site_prefix, conf_basename) + candidate_conf = next( + ( + conffile for conffile in ( + os.path.join(exe_dir, conf_basename), + os.path.join(site_prefix, conf_basename) ) - if os.path.isfile(conffile) - ] + if os.path.isfile(conffile) + ), + None + ) - if candidate_confs: - virtual_conf = candidate_confs[0] + if candidate_conf: + virtual_conf = candidate_conf system_site = "true" # Issue 25185: Use UTF-8, as that's what the venv module uses when # writing the file. diff --git a/Misc/NEWS.d/next/Library/2023-02-19-01-49-46.gh-issue-102038.n3if3D.rst b/Misc/NEWS.d/next/Library/2023-02-19-01-49-46.gh-issue-102038.n3if3D.rst new file mode 100644 index 000000000000..40df20cb5960 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-19-01-49-46.gh-issue-102038.n3if3D.rst @@ -0,0 +1 @@ +Skip a ``stat`` in :mod:`site` if we have already found a ``pyvenv.cfg`` From webhook-mailer at python.org Sun Apr 2 18:52:18 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 02 Apr 2023 22:52:18 -0000 Subject: [Python-checkins] gh-102994: Profile docs has typo in example (GH-103074) Message-ID: https://github.com/python/cpython/commit/823622212eb258fcec467db56f6e726d841297b3 commit: 823622212eb258fcec467db56f6e726d841297b3 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-02T15:52:11-07:00 summary: gh-102994: Profile docs has typo in example (GH-103074) (cherry picked from commit 55decb72c4d2e4ea00ed13da5dd0fd22cecb9083) Co-authored-by: Nouran Ali files: M Doc/library/profile.rst diff --git a/Doc/library/profile.rst b/Doc/library/profile.rst index c2189e02656c..723f927135a0 100644 --- a/Doc/library/profile.rst +++ b/Doc/library/profile.rst @@ -82,7 +82,7 @@ the following:: The first line indicates that 214 calls were monitored. Of those calls, 207 were :dfn:`primitive`, meaning that the call was not induced via recursion. The -next line: ``Ordered by: cumulative name``, indicates that the text string in the +next line: ``Ordered by: cumulative time``, indicates that the text string in the far right column was used to sort the output. The column headings include: ncalls From webhook-mailer at python.org Mon Apr 3 08:44:56 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Mon, 03 Apr 2023 12:44:56 -0000 Subject: [Python-checkins] GH-103182: use vectorcall in `_asyncio` instead of variadic calling APIs (#103175) Message-ID: https://github.com/python/cpython/commit/e6f7d35be7fb65d8624e9411251554c9dee0c931 commit: e6f7d35be7fb65d8624e9411251554c9dee0c931 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-04-03T18:14:32+05:30 summary: GH-103182: use vectorcall in `_asyncio` instead of variadic calling APIs (#103175) files: M Modules/_asynciomodule.c diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 13d98eedf32f..2476dca6f58e 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -355,33 +355,26 @@ call_soon(asyncio_state *state, PyObject *loop, PyObject *func, PyObject *arg, PyObject *ctx) { PyObject *handle; - PyObject *stack[3]; - Py_ssize_t nargs; if (ctx == NULL) { - handle = PyObject_CallMethodObjArgs( - loop, &_Py_ID(call_soon), func, arg, NULL); + PyObject *stack[] = {loop, func, arg}; + size_t nargsf = 3 | PY_VECTORCALL_ARGUMENTS_OFFSET; + handle = PyObject_VectorcallMethod(&_Py_ID(call_soon), stack, nargsf, NULL); } else { - /* Use FASTCALL to pass a keyword-only argument to call_soon */ - - PyObject *callable = PyObject_GetAttr(loop, &_Py_ID(call_soon)); - if (callable == NULL) { - return -1; - } - /* All refs in 'stack' are borrowed. */ - nargs = 1; - stack[0] = func; + PyObject *stack[4]; + size_t nargs = 2; + stack[0] = loop; + stack[1] = func; if (arg != NULL) { - stack[1] = arg; + stack[2] = arg; nargs++; } stack[nargs] = (PyObject *)ctx; - EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_API, callable); - handle = PyObject_Vectorcall(callable, stack, nargs, - state->context_kwname); - Py_DECREF(callable); + size_t nargsf = nargs | PY_VECTORCALL_ARGUMENTS_OFFSET; + handle = PyObject_VectorcallMethod(&_Py_ID(call_soon), stack, nargsf, + state->context_kwname); } if (handle == NULL) { @@ -2359,8 +2352,9 @@ _asyncio_Task_get_stack_impl(TaskObj *self, PyTypeObject *cls, /*[clinic end generated code: output=6774dfc10d3857fa input=8e01c9b2618ae953]*/ { asyncio_state *state = get_asyncio_state_by_cls(cls); - return PyObject_CallFunctionObjArgs( - state->asyncio_task_get_stack_func, self, limit, NULL); + PyObject *stack[] = {(PyObject *)self, limit}; + return PyObject_Vectorcall(state->asyncio_task_get_stack_func, + stack, 2, NULL); } /*[clinic input] @@ -2387,8 +2381,9 @@ _asyncio_Task_print_stack_impl(TaskObj *self, PyTypeObject *cls, /*[clinic end generated code: output=b38affe9289ec826 input=150b35ba2d3a7dee]*/ { asyncio_state *state = get_asyncio_state_by_cls(cls); - return PyObject_CallFunctionObjArgs( - state->asyncio_task_print_stack_func, self, limit, file, NULL); + PyObject *stack[] = {(PyObject *)self, limit, file}; + return PyObject_Vectorcall(state->asyncio_task_print_stack_func, + stack, 3, NULL); } /*[clinic input] From webhook-mailer at python.org Mon Apr 3 11:35:12 2023 From: webhook-mailer at python.org (ambv) Date: Mon, 03 Apr 2023 15:35:12 -0000 Subject: [Python-checkins] gh-101865: Deprecate `co_lnotab` from code objects as per PEP 626 (#101866) Message-ID: https://github.com/python/cpython/commit/2a721258a199e9bcdcee2069719ad9c8f8c0d030 commit: 2a721258a199e9bcdcee2069719ad9c8f8c0d030 branch: main author: Nikita Sobolev committer: ambv date: 2023-04-03T17:35:04+02:00 summary: gh-101865: Deprecate `co_lnotab` from code objects as per PEP 626 (#101866) Co-authored-by: Oleg Iarygin files: A Misc/NEWS.d/next/Core and Builtins/2023-02-21-17-22-06.gh-issue-101865.fwrTOA.rst M Doc/reference/datamodel.rst M Doc/whatsnew/3.12.rst M Lib/test/test_code.py M Objects/codeobject.c diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 1865d09fcaa1..a09d5529c8c6 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -991,7 +991,8 @@ Internal types the filename from which the code was compiled; :attr:`co_firstlineno` is the first line number of the function; :attr:`co_lnotab` is a string encoding the mapping from bytecode offsets to line numbers (for details - see the source code of the interpreter); :attr:`co_stacksize` is the + see the source code of the interpreter, is deprecated since 3.12 + and may be removed in 3.14); :attr:`co_stacksize` is the required stack size; :attr:`co_flags` is an integer encoding a number of flags for the interpreter. diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 3df3ef711a90..88b99828f0be 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -622,6 +622,12 @@ Pending Removal in Python 3.14 functions that have been deprecated since Python 2 but only gained a proper :exc:`DeprecationWarning` in 3.12. Remove them in 3.14. +* Accessing ``co_lnotab`` was deprecated in :pep:`626` since 3.10 + and was planned to be removed in 3.12 + but it only got a proper :exc:`DeprecationWarning` in 3.12. + May be removed in 3.14. + (Contributed by Nikita Sobolev in :gh:`101866`.) + * The *onerror* argument of :func:`shutil.rmtree` is deprecated in 3.12, and will be removed in 3.14. diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py index 0cd1fb3f9728..7543c9ab3421 100644 --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -338,6 +338,13 @@ def func(): new_code = code = func.__code__.replace(co_linetable=b'') self.assertEqual(list(new_code.co_lines()), []) + def test_co_lnotab_is_deprecated(self): # TODO: remove in 3.14 + def func(): + pass + + with self.assertWarns(DeprecationWarning): + func.__code__.co_lnotab + def test_invalid_bytecode(self): def foo(): pass diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-21-17-22-06.gh-issue-101865.fwrTOA.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-21-17-22-06.gh-issue-101865.fwrTOA.rst new file mode 100644 index 000000000000..876cc223a0e7 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-02-21-17-22-06.gh-issue-101865.fwrTOA.rst @@ -0,0 +1,2 @@ +Deprecate ``co_lnotab`` in code objects, schedule it for removal in Python +3.14 diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 65b1d258fb76..755d0b85e7cf 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1921,6 +1921,11 @@ static PyMemberDef code_memberlist[] = { static PyObject * code_getlnotab(PyCodeObject *code, void *closure) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "co_lnotab is deprecated, use co_lines instead.", + 1) < 0) { + return NULL; + } return decode_linetable(code); } From webhook-mailer at python.org Mon Apr 3 14:57:19 2023 From: webhook-mailer at python.org (barneygale) Date: Mon, 03 Apr 2023 18:57:19 -0000 Subject: [Python-checkins] GH-76846, GH-85281: Call `__new__()` and `__init__()` on pathlib subclasses (GH-102789) Message-ID: https://github.com/python/cpython/commit/11c302055a2aab5373c2829d1a8610a64e72ab24 commit: 11c302055a2aab5373c2829d1a8610a64e72ab24 branch: main author: Barney Gale committer: barneygale date: 2023-04-03T19:57:11+01:00 summary: GH-76846, GH-85281: Call `__new__()` and `__init__()` on pathlib subclasses (GH-102789) Fix an issue where `__new__()` and `__init__()` were not called on subclasses of `pathlib.PurePath` and `Path` in some circumstances. Paths are now normalized on-demand. This speeds up path construction, `p.joinpath(q)`, and `p / q`. Co-authored-by: Steve Dower files: A Misc/NEWS.d/next/Library/2023-03-17-19-14-26.gh-issue-76846.KEamjK.rst M Lib/pathlib.py M Lib/test/test_pathlib.py diff --git a/Lib/pathlib.py b/Lib/pathlib.py index a126bf2fe557..490f89f39d26 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -16,7 +16,6 @@ import warnings from _collections_abc import Sequence from errno import ENOENT, ENOTDIR, EBADF, ELOOP -from operator import attrgetter from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO from urllib.parse import quote_from_bytes as urlquote_from_bytes @@ -216,8 +215,8 @@ class _PathParents(Sequence): def __init__(self, path): # We don't store the instance to avoid reference cycles self._pathcls = type(path) - self._drv = path._drv - self._root = path._root + self._drv = path.drive + self._root = path.root self._parts = path._parts def __len__(self): @@ -251,12 +250,12 @@ class PurePath(object): directly, regardless of your system. """ __slots__ = ( - '_drv', '_root', '_parts', + '_raw_path', '_drv', '_root', '_parts_cached', '_str', '_hash', '_parts_tuple', '_parts_normcase_cached', ) _flavour = os.path - def __new__(cls, *args): + def __new__(cls, *args, **kwargs): """Construct a PurePath from one or several strings and or existing PurePath objects. The strings and path objects are combined so as to yield a canonicalized path, which is incorporated into the @@ -264,23 +263,20 @@ def __new__(cls, *args): """ if cls is PurePath: cls = PureWindowsPath if os.name == 'nt' else PurePosixPath - return cls._from_parts(args) + return object.__new__(cls) def __reduce__(self): # Using the parts tuple helps share interned path parts # when pickling related paths. - return (self.__class__, tuple(self._parts)) + return (self.__class__, self.parts) - @classmethod - def _parse_parts(cls, parts): - if not parts: - return '', '', [] - elif len(parts) == 1: - path = os.fspath(parts[0]) + def __init__(self, *args): + if not args: + path = '' + elif len(args) == 1: + path = os.fspath(args[0]) else: - path = cls._flavour.join(*parts) - sep = cls._flavour.sep - altsep = cls._flavour.altsep + path = self._flavour.join(*args) if isinstance(path, str): # Force-cast str subclasses to str (issue #21127) path = str(path) @@ -289,6 +285,14 @@ def _parse_parts(cls, parts): "argument should be a str or an os.PathLike " "object where __fspath__ returns a str, " f"not {type(path).__name__!r}") + self._raw_path = path + + @classmethod + def _parse_path(cls, path): + if not path: + return '', '', [] + sep = cls._flavour.sep + altsep = cls._flavour.altsep if altsep: path = path.replace(altsep, sep) drv, root, rel = cls._flavour.splitroot(path) @@ -299,21 +303,20 @@ def _parse_parts(cls, parts): parsed = [sys.intern(x) for x in unfiltered_parsed if x and x != '.'] return drv, root, parsed - @classmethod - def _from_parts(cls, args): - self = object.__new__(cls) - drv, root, parts = self._parse_parts(args) + def _load_parts(self): + drv, root, parts = self._parse_path(self._raw_path) self._drv = drv self._root = root - self._parts = parts - return self + self._parts_cached = parts @classmethod def _from_parsed_parts(cls, drv, root, parts): - self = object.__new__(cls) + path = cls._format_parsed_parts(drv, root, parts) + self = cls(path) + self._str = path or '.' self._drv = drv self._root = root - self._parts = parts + self._parts_cached = parts return self @classmethod @@ -330,7 +333,7 @@ def __str__(self): try: return self._str except AttributeError: - self._str = self._format_parsed_parts(self._drv, self._root, + self._str = self._format_parsed_parts(self.drive, self.root, self._parts) or '.' return self._str @@ -356,7 +359,7 @@ def as_uri(self): if not self.is_absolute(): raise ValueError("relative path can't be expressed as a file URI") - drive = self._drv + drive = self.drive if len(drive) == 2 and drive[1] == ':': # It's a path on a local drive => 'file:///c:/a/b' prefix = 'file:///' + drive @@ -412,23 +415,43 @@ def __ge__(self, other): return NotImplemented return self._parts_normcase >= other._parts_normcase - drive = property(attrgetter('_drv'), - doc="""The drive prefix (letter or UNC path), if any.""") + @property + def drive(self): + """The drive prefix (letter or UNC path), if any.""" + try: + return self._drv + except AttributeError: + self._load_parts() + return self._drv + + @property + def root(self): + """The root of the path, if any.""" + try: + return self._root + except AttributeError: + self._load_parts() + return self._root - root = property(attrgetter('_root'), - doc="""The root of the path, if any.""") + @property + def _parts(self): + try: + return self._parts_cached + except AttributeError: + self._load_parts() + return self._parts_cached @property def anchor(self): """The concatenation of the drive and root, or ''.""" - anchor = self._drv + self._root + anchor = self.drive + self.root return anchor @property def name(self): """The final path component, if any.""" parts = self._parts - if len(parts) == (1 if (self._drv or self._root) else 0): + if len(parts) == (1 if (self.drive or self.root) else 0): return '' return parts[-1] @@ -477,7 +500,7 @@ def with_name(self, name): drv, root, tail = f.splitroot(name) if drv or root or not tail or f.sep in tail or (f.altsep and f.altsep in tail): raise ValueError("Invalid name %r" % (name)) - return self._from_parsed_parts(self._drv, self._root, + return self._from_parsed_parts(self.drive, self.root, self._parts[:-1] + [name]) def with_stem(self, stem): @@ -502,7 +525,7 @@ def with_suffix(self, suffix): name = name + suffix else: name = name[:-len(old_suffix)] + suffix - return self._from_parsed_parts(self._drv, self._root, + return self._from_parsed_parts(self.drive, self.root, self._parts[:-1] + [name]) def relative_to(self, other, /, *_deprecated, walk_up=False): @@ -561,22 +584,7 @@ def joinpath(self, *args): paths) or a totally different path (if one of the arguments is anchored). """ - drv1, root1, parts1 = self._drv, self._root, self._parts - drv2, root2, parts2 = self._parse_parts(args) - if root2: - if not drv2 and drv1: - return self._from_parsed_parts(drv1, root2, [drv1 + root2] + parts2[1:]) - else: - return self._from_parsed_parts(drv2, root2, parts2) - elif drv2: - if drv2 == drv1 or self._flavour.normcase(drv2) == self._flavour.normcase(drv1): - # Same drive => second path is relative to the first. - return self._from_parsed_parts(drv1, root1, parts1 + parts2[1:]) - else: - return self._from_parsed_parts(drv2, root2, parts2) - else: - # Second path is non-anchored (common case). - return self._from_parsed_parts(drv1, root1, parts1 + parts2) + return self.__class__(self._raw_path, *args) def __truediv__(self, key): try: @@ -586,15 +594,15 @@ def __truediv__(self, key): def __rtruediv__(self, key): try: - return self._from_parts([key] + self._parts) + return type(self)(key, self._raw_path) except TypeError: return NotImplemented @property def parent(self): """The logical parent of the path.""" - drv = self._drv - root = self._root + drv = self.drive + root = self.root parts = self._parts if len(parts) == 1 and (drv or root): return self @@ -610,7 +618,7 @@ def is_absolute(self): a drive).""" # ntpath.isabs() is defective - see GH-44626 . if self._flavour is ntpath: - return bool(self._drv and self._root) + return bool(self.drive and self.root) return self._flavour.isabs(self) def is_reserved(self): @@ -634,7 +642,7 @@ def match(self, path_pattern): Return True if this path matches the given pattern. """ path_pattern = self._flavour.normcase(path_pattern) - drv, root, pat_parts = self._parse_parts((path_pattern,)) + drv, root, pat_parts = self._parse_path(path_pattern) if not pat_parts: raise ValueError("empty pattern") parts = self._parts_normcase @@ -687,20 +695,23 @@ class Path(PurePath): """ __slots__ = () - def __new__(cls, *args, **kwargs): + def __init__(self, *args, **kwargs): if kwargs: msg = ("support for supplying keyword arguments to pathlib.PurePath " "is deprecated and scheduled for removal in Python {remove}") warnings._deprecated("pathlib.PurePath(**kwargs)", msg, remove=(3, 14)) + super().__init__(*args) + + def __new__(cls, *args, **kwargs): if cls is Path: cls = WindowsPath if os.name == 'nt' else PosixPath - return cls._from_parts(args) + return object.__new__(cls) def _make_child_relpath(self, part): # This is an optimization used for dir walking. `part` must be # a single part relative to this path. parts = self._parts + [part] - return self._from_parsed_parts(self._drv, self._root, parts) + return self._from_parsed_parts(self.drive, self.root, parts) def __enter__(self): # In previous versions of pathlib, __exit__() marked this path as @@ -770,7 +781,7 @@ def glob(self, pattern): sys.audit("pathlib.Path.glob", self, pattern) if not pattern: raise ValueError("Unacceptable pattern: {!r}".format(pattern)) - drv, root, pattern_parts = self._parse_parts((pattern,)) + drv, root, pattern_parts = self._parse_path(pattern) if drv or root: raise NotImplementedError("Non-relative patterns are unsupported") if pattern[-1] in (self._flavour.sep, self._flavour.altsep): @@ -785,7 +796,7 @@ def rglob(self, pattern): this subtree. """ sys.audit("pathlib.Path.rglob", self, pattern) - drv, root, pattern_parts = self._parse_parts((pattern,)) + drv, root, pattern_parts = self._parse_path(pattern) if drv or root: raise NotImplementedError("Non-relative patterns are unsupported") if pattern and pattern[-1] in (self._flavour.sep, self._flavour.altsep): @@ -802,12 +813,12 @@ def absolute(self): """ if self.is_absolute(): return self - elif self._drv: + elif self.drive: # There is a CWD on each drive-letter drive. - cwd = self._flavour.abspath(self._drv) + cwd = self._flavour.abspath(self.drive) else: cwd = os.getcwd() - return self._from_parts([cwd] + self._parts) + return type(self)(cwd, self._raw_path) def resolve(self, strict=False): """ @@ -825,7 +836,7 @@ def check_eloop(e): except OSError as e: check_eloop(e) raise - p = self._from_parts((s,)) + p = type(self)(s) # In non-strict mode, realpath() doesn't raise on symlink loops. # Ensure we get an exception by calling stat() @@ -915,7 +926,7 @@ def readlink(self): """ if not hasattr(os, "readlink"): raise NotImplementedError("os.readlink() not available on this system") - return self._from_parts((os.readlink(self),)) + return type(self)(os.readlink(self)) def touch(self, mode=0o666, exist_ok=True): """ @@ -1184,12 +1195,12 @@ def expanduser(self): """ Return a new path with expanded ~ and ~user constructs (as returned by os.path.expanduser) """ - if (not (self._drv or self._root) and + if (not (self.drive or self.root) and self._parts and self._parts[0][:1] == '~'): homedir = self._flavour.expanduser(self._parts[0]) if homedir[:1] == "~": raise RuntimeError("Could not determine home directory.") - drv, root, parts = self._parse_parts((homedir,)) + drv, root, parts = self._parse_path(homedir) return self._from_parsed_parts(drv, root, parts + self._parts[1:]) return self diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 3041630da678..8b6e012b730d 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -27,7 +27,9 @@ class _BaseFlavourTest(object): def _check_parse_parts(self, arg, expected): - f = self.cls._parse_parts + def f(parts): + path = self.cls(*parts)._raw_path + return self.cls._parse_path(path) sep = self.flavour.sep altsep = self.flavour.altsep actual = f([x.replace('/', sep) for x in arg]) @@ -136,6 +138,14 @@ def test_parse_parts(self): # Tests for the pure classes. # +class _BasePurePathSubclass(object): + init_called = False + + def __init__(self, *args): + super().__init__(*args) + self.init_called = True + + class _BasePurePathTest(object): # Keys are canonical paths, values are list of tuples of arguments @@ -221,6 +231,21 @@ def test_str_subclass_common(self): self._check_str_subclass('a/b.txt') self._check_str_subclass('/a/b.txt') + def test_init_called_common(self): + class P(_BasePurePathSubclass, self.cls): + pass + p = P('foo', 'bar') + self.assertTrue((p / 'foo').init_called) + self.assertTrue(('foo' / p).init_called) + self.assertTrue(p.joinpath('foo').init_called) + self.assertTrue(p.with_name('foo').init_called) + self.assertTrue(p.with_stem('foo').init_called) + self.assertTrue(p.with_suffix('.foo').init_called) + self.assertTrue(p.relative_to('foo').init_called) + self.assertTrue(p.parent.init_called) + for parent in p.parents: + self.assertTrue(parent.init_called) + def test_join_common(self): P = self.cls p = P('a/b') diff --git a/Misc/NEWS.d/next/Library/2023-03-17-19-14-26.gh-issue-76846.KEamjK.rst b/Misc/NEWS.d/next/Library/2023-03-17-19-14-26.gh-issue-76846.KEamjK.rst new file mode 100644 index 000000000000..9fba11f074ee --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-17-19-14-26.gh-issue-76846.KEamjK.rst @@ -0,0 +1,3 @@ +Fix issue where ``__new__()`` and ``__init__()`` methods of +:class:`pathlib.PurePath` and :class:`~pathlib.Path` subclasses were not +called in some circumstances. From webhook-mailer at python.org Mon Apr 3 14:59:55 2023 From: webhook-mailer at python.org (hugovk) Date: Mon, 03 Apr 2023 18:59:55 -0000 Subject: [Python-checkins] gh-101100: Use list of 'dirty' docs, with warnings, instead of a clean list (#103191) Message-ID: https://github.com/python/cpython/commit/24facd60f6e5458cc783e429fe63d6a80d476f84 commit: 24facd60f6e5458cc783e429fe63d6a80d476f84 branch: main author: Hugo van Kemenade committer: hugovk date: 2023-04-03T21:59:47+03:00 summary: gh-101100: Use list of 'dirty' docs, with warnings, instead of a clean list (#103191) Co-authored-by: Alex Waygood files: A Doc/tools/.nitignore D Doc/tools/clean-files.txt M Doc/tools/touch-clean-files.py diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore new file mode 100644 index 000000000000..f6fe8df97810 --- /dev/null +++ b/Doc/tools/.nitignore @@ -0,0 +1,304 @@ +# All RST files under Doc/ -- except these -- must pass Sphinx nit-picky mode, +# as tested on the CI via touch-clean-files.py in doc.yml. +# Add blank lines between files and keep them sorted lexicographically +# to help avoid merge conflicts. + +Doc/c-api/allocation.rst +Doc/c-api/apiabiversion.rst +Doc/c-api/arg.rst +Doc/c-api/bool.rst +Doc/c-api/buffer.rst +Doc/c-api/bytes.rst +Doc/c-api/call.rst +Doc/c-api/capsule.rst +Doc/c-api/cell.rst +Doc/c-api/code.rst +Doc/c-api/codec.rst +Doc/c-api/complex.rst +Doc/c-api/conversion.rst +Doc/c-api/datetime.rst +Doc/c-api/descriptor.rst +Doc/c-api/dict.rst +Doc/c-api/exceptions.rst +Doc/c-api/file.rst +Doc/c-api/float.rst +Doc/c-api/gcsupport.rst +Doc/c-api/import.rst +Doc/c-api/init.rst +Doc/c-api/init_config.rst +Doc/c-api/intro.rst +Doc/c-api/iterator.rst +Doc/c-api/long.rst +Doc/c-api/mapping.rst +Doc/c-api/marshal.rst +Doc/c-api/memory.rst +Doc/c-api/memoryview.rst +Doc/c-api/module.rst +Doc/c-api/none.rst +Doc/c-api/object.rst +Doc/c-api/refcounting.rst +Doc/c-api/sequence.rst +Doc/c-api/set.rst +Doc/c-api/stable.rst +Doc/c-api/structures.rst +Doc/c-api/sys.rst +Doc/c-api/tuple.rst +Doc/c-api/type.rst +Doc/c-api/typehints.rst +Doc/c-api/typeobj.rst +Doc/c-api/unicode.rst +Doc/c-api/veryhigh.rst +Doc/c-api/weakref.rst +Doc/extending/embedding.rst +Doc/extending/extending.rst +Doc/extending/newtypes.rst +Doc/extending/newtypes_tutorial.rst +Doc/faq/design.rst +Doc/faq/extending.rst +Doc/faq/gui.rst +Doc/faq/library.rst +Doc/faq/programming.rst +Doc/glossary.rst +Doc/howto/argparse.rst +Doc/howto/curses.rst +Doc/howto/descriptor.rst +Doc/howto/enum.rst +Doc/howto/functional.rst +Doc/howto/instrumentation.rst +Doc/howto/isolating-extensions.rst +Doc/howto/logging-cookbook.rst +Doc/howto/logging.rst +Doc/howto/regex.rst +Doc/howto/sorting.rst +Doc/howto/unicode.rst +Doc/howto/urllib2.rst +Doc/install/index.rst +Doc/library/2to3.rst +Doc/library/__future__.rst +Doc/library/_thread.rst +Doc/library/abc.rst +Doc/library/aifc.rst +Doc/library/argparse.rst +Doc/library/ast.rst +Doc/library/asyncio-dev.rst +Doc/library/asyncio-eventloop.rst +Doc/library/asyncio-extending.rst +Doc/library/asyncio-future.rst +Doc/library/asyncio-policy.rst +Doc/library/asyncio-stream.rst +Doc/library/asyncio-subprocess.rst +Doc/library/asyncio-task.rst +Doc/library/audioop.rst +Doc/library/bdb.rst +Doc/library/bisect.rst +Doc/library/bz2.rst +Doc/library/calendar.rst +Doc/library/cgi.rst +Doc/library/chunk.rst +Doc/library/cmath.rst +Doc/library/cmd.rst +Doc/library/code.rst +Doc/library/codecs.rst +Doc/library/codeop.rst +Doc/library/collections.abc.rst +Doc/library/collections.rst +Doc/library/compileall.rst +Doc/library/concurrent.futures.rst +Doc/library/concurrent.rst +Doc/library/configparser.rst +Doc/library/constants.rst +Doc/library/contextlib.rst +Doc/library/copy.rst +Doc/library/csv.rst +Doc/library/ctypes.rst +Doc/library/curses.ascii.rst +Doc/library/curses.rst +Doc/library/dataclasses.rst +Doc/library/datetime.rst +Doc/library/dbm.rst +Doc/library/decimal.rst +Doc/library/devmode.rst +Doc/library/difflib.rst +Doc/library/dis.rst +Doc/library/doctest.rst +Doc/library/email.charset.rst +Doc/library/email.compat32-message.rst +Doc/library/email.encoders.rst +Doc/library/email.errors.rst +Doc/library/email.generator.rst +Doc/library/email.headerregistry.rst +Doc/library/email.message.rst +Doc/library/email.mime.rst +Doc/library/email.parser.rst +Doc/library/email.policy.rst +Doc/library/enum.rst +Doc/library/exceptions.rst +Doc/library/faulthandler.rst +Doc/library/fcntl.rst +Doc/library/filecmp.rst +Doc/library/fileinput.rst +Doc/library/fractions.rst +Doc/library/ftplib.rst +Doc/library/functions.rst +Doc/library/functools.rst +Doc/library/getopt.rst +Doc/library/getpass.rst +Doc/library/gettext.rst +Doc/library/graphlib.rst +Doc/library/gzip.rst +Doc/library/hashlib.rst +Doc/library/http.client.rst +Doc/library/http.cookiejar.rst +Doc/library/http.cookies.rst +Doc/library/http.server.rst +Doc/library/idle.rst +Doc/library/imp.rst +Doc/library/importlib.resources.abc.rst +Doc/library/importlib.resources.rst +Doc/library/importlib.rst +Doc/library/inspect.rst +Doc/library/io.rst +Doc/library/json.rst +Doc/library/locale.rst +Doc/library/logging.config.rst +Doc/library/logging.handlers.rst +Doc/library/logging.rst +Doc/library/lzma.rst +Doc/library/mailbox.rst +Doc/library/mmap.rst +Doc/library/msilib.rst +Doc/library/msvcrt.rst +Doc/library/multiprocessing.rst +Doc/library/multiprocessing.shared_memory.rst +Doc/library/netrc.rst +Doc/library/nntplib.rst +Doc/library/numbers.rst +Doc/library/operator.rst +Doc/library/optparse.rst +Doc/library/os.path.rst +Doc/library/os.rst +Doc/library/ossaudiodev.rst +Doc/library/pickle.rst +Doc/library/pickletools.rst +Doc/library/pkgutil.rst +Doc/library/platform.rst +Doc/library/plistlib.rst +Doc/library/poplib.rst +Doc/library/posix.rst +Doc/library/pprint.rst +Doc/library/profile.rst +Doc/library/pty.rst +Doc/library/py_compile.rst +Doc/library/pyclbr.rst +Doc/library/pydoc.rst +Doc/library/pyexpat.rst +Doc/library/random.rst +Doc/library/re.rst +Doc/library/readline.rst +Doc/library/reprlib.rst +Doc/library/resource.rst +Doc/library/rlcompleter.rst +Doc/library/sched.rst +Doc/library/select.rst +Doc/library/selectors.rst +Doc/library/shelve.rst +Doc/library/shutil.rst +Doc/library/signal.rst +Doc/library/site.rst +Doc/library/smtplib.rst +Doc/library/socket.rst +Doc/library/socketserver.rst +Doc/library/ssl.rst +Doc/library/stat.rst +Doc/library/stdtypes.rst +Doc/library/string.rst +Doc/library/struct.rst +Doc/library/subprocess.rst +Doc/library/sunau.rst +Doc/library/sys.rst +Doc/library/sys_path_init.rst +Doc/library/sysconfig.rst +Doc/library/syslog.rst +Doc/library/tarfile.rst +Doc/library/telnetlib.rst +Doc/library/tempfile.rst +Doc/library/termios.rst +Doc/library/test.rst +Doc/library/textwrap.rst +Doc/library/threading.rst +Doc/library/time.rst +Doc/library/tkinter.rst +Doc/library/tkinter.scrolledtext.rst +Doc/library/tkinter.tix.rst +Doc/library/tkinter.ttk.rst +Doc/library/traceback.rst +Doc/library/tty.rst +Doc/library/turtle.rst +Doc/library/unittest.mock-examples.rst +Doc/library/unittest.mock.rst +Doc/library/unittest.rst +Doc/library/urllib.error.rst +Doc/library/urllib.parse.rst +Doc/library/urllib.request.rst +Doc/library/uuid.rst +Doc/library/wave.rst +Doc/library/weakref.rst +Doc/library/webbrowser.rst +Doc/library/winreg.rst +Doc/library/winsound.rst +Doc/library/wsgiref.rst +Doc/library/xdrlib.rst +Doc/library/xml.dom.minidom.rst +Doc/library/xml.dom.pulldom.rst +Doc/library/xml.dom.rst +Doc/library/xml.etree.elementtree.rst +Doc/library/xml.rst +Doc/library/xml.sax.handler.rst +Doc/library/xml.sax.reader.rst +Doc/library/xml.sax.rst +Doc/library/xml.sax.utils.rst +Doc/library/xmlrpc.client.rst +Doc/library/xmlrpc.rst +Doc/library/xmlrpc.server.rst +Doc/library/zlib.rst +Doc/license.rst +Doc/reference/compound_stmts.rst +Doc/reference/datamodel.rst +Doc/reference/expressions.rst +Doc/reference/import.rst +Doc/reference/lexical_analysis.rst +Doc/reference/simple_stmts.rst +Doc/tutorial/appendix.rst +Doc/tutorial/classes.rst +Doc/tutorial/controlflow.rst +Doc/tutorial/datastructures.rst +Doc/tutorial/errors.rst +Doc/tutorial/inputoutput.rst +Doc/tutorial/interactive.rst +Doc/tutorial/introduction.rst +Doc/tutorial/modules.rst +Doc/tutorial/stdlib2.rst +Doc/using/cmdline.rst +Doc/using/configure.rst +Doc/using/unix.rst +Doc/using/windows.rst +Doc/whatsnew/2.0.rst +Doc/whatsnew/2.1.rst +Doc/whatsnew/2.2.rst +Doc/whatsnew/2.3.rst +Doc/whatsnew/2.4.rst +Doc/whatsnew/2.5.rst +Doc/whatsnew/2.6.rst +Doc/whatsnew/2.7.rst +Doc/whatsnew/3.0.rst +Doc/whatsnew/3.1.rst +Doc/whatsnew/3.2.rst +Doc/whatsnew/3.3.rst +Doc/whatsnew/3.4.rst +Doc/whatsnew/3.5.rst +Doc/whatsnew/3.6.rst +Doc/whatsnew/3.7.rst +Doc/whatsnew/3.8.rst +Doc/whatsnew/3.9.rst +Doc/whatsnew/3.10.rst +Doc/whatsnew/3.11.rst diff --git a/Doc/tools/clean-files.txt b/Doc/tools/clean-files.txt deleted file mode 100644 index baef7c2f8958..000000000000 --- a/Doc/tools/clean-files.txt +++ /dev/null @@ -1,366 +0,0 @@ -# These files must pass Sphinx nit-picky mode, as tested on the CI -# via touch-clean-files.py in doc.yml. -# Add blank lines between files and keep them sorted lexicographically -# to help avoid merge conflicts. - -Doc/about.rst - -Doc/bugs.rst - -Doc/c-api/abstract.rst - -Doc/c-api/bytearray.rst - -Doc/c-api/concrete.rst - -Doc/c-api/contextvars.rst - -Doc/c-api/coro.rst - -Doc/c-api/frame.rst - -Doc/c-api/function.rst - -Doc/c-api/gen.rst - -Doc/c-api/index.rst - -Doc/c-api/iter.rst - -Doc/c-api/list.rst - -Doc/c-api/method.rst - -Doc/c-api/number.rst - -Doc/c-api/objbuffer.rst - -Doc/c-api/objimpl.rst - -Doc/c-api/reflection.rst - -Doc/c-api/slice.rst - -Doc/c-api/utilities.rst - -Doc/contents.rst - -Doc/copyright.rst - -Doc/distributing/index.rst - -Doc/extending/building.rst - -Doc/extending/index.rst - -Doc/extending/windows.rst - -Doc/faq/general.rst - -Doc/faq/index.rst - -Doc/faq/installed.rst - -Doc/faq/windows.rst - -Doc/howto/annotations.rst - -Doc/howto/clinic.rst - -Doc/howto/cporting.rst - -Doc/howto/index.rst - -Doc/howto/ipaddress.rst - -Doc/howto/perf_profiling.rst - -Doc/howto/pyporting.rst - -Doc/howto/sockets.rst - -Doc/installing/index.rst - -Doc/library/__main__.rst - -Doc/library/allos.rst - -Doc/library/archiving.rst - -Doc/library/array.rst - -Doc/library/asyncio-api-index.rst - -Doc/library/asyncio-exceptions.rst - -Doc/library/asyncio-llapi-index.rst - -Doc/library/asyncio-platforms.rst - -Doc/library/asyncio-protocol.rst - -Doc/library/asyncio-queue.rst - -Doc/library/asyncio-runner.rst - -Doc/library/asyncio-sync.rst - -Doc/library/asyncio.rst - -Doc/library/atexit.rst - -Doc/library/audit_events.rst - -Doc/library/base64.rst - -Doc/library/binary.rst - -Doc/library/binascii.rst - -Doc/library/builtins.rst - -Doc/library/cgitb.rst - -Doc/library/colorsys.rst - -Doc/library/concurrency.rst - -Doc/library/contextvars.rst - -Doc/library/copyreg.rst - -Doc/library/crypt.rst - -Doc/library/crypto.rst - -Doc/library/curses.panel.rst - -Doc/library/custominterp.rst - -Doc/library/datatypes.rst - -Doc/library/debug.rst - -Doc/library/development.rst - -Doc/library/dialog.rst - -Doc/library/distribution.rst - -Doc/library/email.contentmanager.rst - -Doc/library/email.examples.rst - -Doc/library/email.header.rst - -Doc/library/email.iterators.rst - -Doc/library/email.rst - -Doc/library/email.utils.rst - -Doc/library/ensurepip.rst - -Doc/library/errno.rst - -Doc/library/fileformats.rst - -Doc/library/filesys.rst - -Doc/library/fnmatch.rst - -Doc/library/frameworks.rst - -Doc/library/functional.rst - -Doc/library/gc.rst - -Doc/library/glob.rst - -Doc/library/grp.rst - -Doc/library/heapq.rst - -Doc/library/hmac.rst - -Doc/library/html.entities.rst - -Doc/library/html.parser.rst - -Doc/library/html.rst - -Doc/library/http.rst - -Doc/library/i18n.rst - -Doc/library/imaplib.rst - -Doc/library/imghdr.rst - -Doc/library/importlib.metadata.rst - -Doc/library/index.rst - -Doc/library/internet.rst - -Doc/library/intro.rst - -Doc/library/ipaddress.rst - -Doc/library/ipc.rst - -Doc/library/itertools.rst - -Doc/library/keyword.rst - -Doc/library/language.rst - -Doc/library/linecache.rst - -Doc/library/mailcap.rst - -Doc/library/markup.rst - -Doc/library/marshal.rst - -Doc/library/math.rst - -Doc/library/mimetypes.rst - -Doc/library/mm.rst - -Doc/library/modulefinder.rst - -Doc/library/modules.rst - -Doc/library/netdata.rst - -Doc/library/nis.rst - -Doc/library/numeric.rst - -Doc/library/pathlib.rst - -Doc/library/pdb.rst - -Doc/library/persistence.rst - -Doc/library/pipes.rst - -Doc/library/pwd.rst - -Doc/library/python.rst - -Doc/library/queue.rst - -Doc/library/quopri.rst - -Doc/library/runpy.rst - -Doc/library/secrets.rst - -Doc/library/security_warnings.rst - -Doc/library/shlex.rst - -Doc/library/sndhdr.rst - -Doc/library/spwd.rst - -Doc/library/sqlite3.rst - -Doc/library/statistics.rst - -Doc/library/stringprep.rst - -Doc/library/superseded.rst - -Doc/library/symtable.rst - -Doc/library/tabnanny.rst - -Doc/library/text.rst - -Doc/library/timeit.rst - -Doc/library/tk.rst - -Doc/library/tkinter.colorchooser.rst - -Doc/library/tkinter.dnd.rst - -Doc/library/tkinter.font.rst - -Doc/library/tkinter.messagebox.rst - -#Doc/library/token.rst - -Doc/library/tokenize.rst - -Doc/library/tomllib.rst - -Doc/library/trace.rst - -Doc/library/tracemalloc.rst - -Doc/library/types.rst - -Doc/library/typing.rst - -Doc/library/unicodedata.rst - -Doc/library/unix.rst - -Doc/library/urllib.robotparser.rst - -Doc/library/urllib.rst - -Doc/library/uu.rst - -Doc/library/venv.rst - -Doc/library/warnings.rst - -Doc/library/windows.rst - -Doc/library/zipapp.rst - -Doc/library/zipfile.rst - -Doc/library/zipimport.rst - -Doc/library/zoneinfo.rst - -Doc/reference/executionmodel.rst - -Doc/reference/grammar.rst - -Doc/reference/index.rst - -Doc/reference/introduction.rst - -Doc/reference/toplevel_components.rst - -Doc/tutorial/appetite.rst - -Doc/tutorial/floatingpoint.rst - -Doc/tutorial/index.rst - -Doc/tutorial/interpreter.rst - -Doc/tutorial/stdlib.rst - -Doc/tutorial/venv.rst - -Doc/tutorial/whatnow.rst - -Doc/using/editors.rst - -Doc/using/index.rst - -Doc/using/mac.rst - -Doc/whatsnew/3.12.rst - -Doc/whatsnew/index.rst diff --git a/Doc/tools/touch-clean-files.py b/Doc/tools/touch-clean-files.py index 9f55e9446ba7..19bc1be31deb 100644 --- a/Doc/tools/touch-clean-files.py +++ b/Doc/tools/touch-clean-files.py @@ -6,16 +6,39 @@ from pathlib import Path -# Input file has blank line between entries to reduce merge conflicts -with Path("Doc/tools/clean-files.txt").open() as clean_files: - CLEAN = [ +wrong_directory_msg = "Must run this script from the repo root" +assert Path("Doc").exists() and Path("Doc").is_dir(), wrong_directory_msg + +# Exclude these whether they're dirty or clean, +# because they trigger a rebuild of dirty files. +EXCLUDE_FILES = { + Path("Doc/whatsnew/changelog.rst"), +} + +# Subdirectories of Doc/ to exclude. +EXCLUDE_SUBDIRS = { + ".env", + ".venv", + "env", + "includes", + "venv", +} + +ALL_RST = { + rst for rst in Path("Doc/").rglob("*.rst") if rst.parts[1] not in EXCLUDE_SUBDIRS +} + +with Path("Doc/tools/.nitignore").open() as clean_files: + DIRTY = { Path(filename.strip()) for filename in clean_files if filename.strip() and not filename.startswith("#") - ] + } + +CLEAN = ALL_RST - DIRTY - EXCLUDE_FILES print("Touching:") -for filename in CLEAN: +for filename in sorted(CLEAN): print(filename) filename.touch() print(f"Touched {len(CLEAN)} files") From webhook-mailer at python.org Mon Apr 3 17:51:50 2023 From: webhook-mailer at python.org (ethanfurman) Date: Mon, 03 Apr 2023 21:51:50 -0000 Subject: [Python-checkins] gh-103215: Remove redundant if stmt from `enum.EnumType._find_data_type_` (GH-103222) Message-ID: https://github.com/python/cpython/commit/d3a7732dd54c27ae523bef73efbb0c580ce2fbc0 commit: d3a7732dd54c27ae523bef73efbb0c580ce2fbc0 branch: main author: Sadra Barikbin committer: ethanfurman date: 2023-04-03T14:51:43-07:00 summary: gh-103215: Remove redundant if stmt from `enum.EnumType._find_data_type_` (GH-103222) files: M Lib/enum.py diff --git a/Lib/enum.py b/Lib/enum.py index 4e231e7e8ea7..b8ea7af9e747 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -987,8 +987,6 @@ def _find_data_type_(mcls, class_name, bases): data_types.add(base._member_type_) break elif '__new__' in base.__dict__ or '__init__' in base.__dict__: - if isinstance(base, EnumType): - continue data_types.add(candidate or base) break else: From webhook-mailer at python.org Mon Apr 3 17:57:49 2023 From: webhook-mailer at python.org (ethanfurman) Date: Mon, 03 Apr 2023 21:57:49 -0000 Subject: [Python-checkins] gh-98298, gh-74730: [Enum] update docs (GH-103163) Message-ID: https://github.com/python/cpython/commit/5ffc1e5a21de9a30566095386236db44695d184a commit: 5ffc1e5a21de9a30566095386236db44695d184a branch: main author: Ethan Furman committer: ethanfurman date: 2023-04-03T14:57:42-07:00 summary: gh-98298, gh-74730: [Enum] update docs (GH-103163) fix FlagBoundary statements add warning about reloading modules and enum identity files: M Doc/howto/enum.rst M Doc/library/enum.rst M Lib/enum.py diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst index 4525acb04503..fc8ea55069a9 100644 --- a/Doc/howto/enum.rst +++ b/Doc/howto/enum.rst @@ -372,6 +372,11 @@ below):: >>> Color.BLUE == 2 False +.. warning:: + + It is possible to reload modules -- if a reloaded module contains + enums, they will be recreated, and the new members may not + compare identical/equal to the original members. Allowed members and attributes of enumerations ---------------------------------------------- diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index 24b6dbfe37cd..c690c837309e 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -141,9 +141,8 @@ Module Contents :func:`global_enum` Modify the :class:`str() ` and :func:`repr` of an enum - to show its members as belonging to the module instead of its class. - Should only be used if the enum members will be exported to the - module global namespace. + to show its members as belonging to the module instead of its class, + and export the enum members to the global namespace. :func:`show_flag_values` @@ -170,6 +169,27 @@ Data Types final *enum*, as well as creating the enum members, properly handling duplicates, providing iteration over the enum class, etc. + .. method:: EnumType.__call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None) + + This method is called in two different ways: + + * to look up an existing member: + + :cls: The enum class being called. + :value: The value to lookup. + + * to use the ``cls`` enum to create a new enum (only if the existing enum + does not have any members): + + :cls: The enum class being called. + :value: The name of the new Enum to create. + :names: The names/values of the members for the new Enum. + :module: The name of the module the new Enum is created in. + :qualname: The actual location in the module where this Enum can be found. + :type: A mix-in type for the new Enum. + :start: The first integer value for the Enum (used by :class:`auto`). + :boundary: How to handle out-of-range values from bit operations (:class:`Flag` only). + .. method:: EnumType.__contains__(cls, member) Returns ``True`` if member belongs to the ``cls``:: @@ -255,26 +275,6 @@ Data Types names will also be removed from the completed enumeration. See :ref:`TimePeriod ` for an example. - .. method:: Enum.__call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None) - - This method is called in two different ways: - - * to look up an existing member: - - :cls: The enum class being called. - :value: The value to lookup. - - * to use the ``cls`` enum to create a new enum: - - :cls: The enum class being called. - :value: The name of the new Enum to create. - :names: The names/values of the members for the new Enum. - :module: The name of the module the new Enum is created in. - :qualname: The actual location in the module where this Enum can be found. - :type: A mix-in type for the new Enum. - :start: The first integer value for the Enum (used by :class:`auto`). - :boundary: How to handle out-of-range values from bit operations (:class:`Flag` only). - .. method:: Enum.__dir__(self) Returns ``['__class__', '__doc__', '__module__', 'name', 'value']`` and @@ -728,7 +728,6 @@ Data Types .. attribute:: EJECT Out-of-range values lose their *Flag* membership and revert to :class:`int`. - This is the default for :class:`IntFlag`:: >>> from enum import Flag, EJECT, auto >>> class EjectFlag(Flag, boundary=EJECT): @@ -741,8 +740,8 @@ Data Types .. attribute:: KEEP - Out-of-range values are kept, and the *Flag* membership is kept. This is - used for some stdlib flags:: + Out-of-range values are kept, and the *Flag* membership is kept. + This is the default for :class:`IntFlag`:: >>> from enum import Flag, KEEP, auto >>> class KeepFlag(Flag, boundary=KEEP): diff --git a/Lib/enum.py b/Lib/enum.py index b8ea7af9e747..9d836c716d84 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1301,10 +1301,10 @@ def _reduce_ex_by_global_name(self, proto): class FlagBoundary(StrEnum): """ control how out of range values are handled - "strict" -> error is raised [default for Flag] - "conform" -> extra bits are discarded - "eject" -> lose flag status [default for IntFlag] - "keep" -> keep flag status and all bits + "strict" -> error is raised + "conform" -> extra bits are discarded [default for Flag] + "eject" -> lose flag status + "keep" -> keep flag status and all bits [default for IntFlag] """ STRICT = auto() CONFORM = auto() From webhook-mailer at python.org Mon Apr 3 18:27:41 2023 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Apr 2023 22:27:41 -0000 Subject: [Python-checkins] gh-98298, gh-74730: [Enum] update docs (GH-103163) Message-ID: https://github.com/python/cpython/commit/cf72cc25f600183c69e3639e78cfae3571f8d4d0 commit: cf72cc25f600183c69e3639e78cfae3571f8d4d0 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-03T15:27:33-07:00 summary: gh-98298, gh-74730: [Enum] update docs (GH-103163) fix FlagBoundary statements add warning about reloading modules and enum identity (cherry picked from commit 5ffc1e5a21de9a30566095386236db44695d184a) Co-authored-by: Ethan Furman files: M Doc/howto/enum.rst M Doc/library/enum.rst M Lib/enum.py diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst index 990d006b3e98..f2a10c03fa88 100644 --- a/Doc/howto/enum.rst +++ b/Doc/howto/enum.rst @@ -371,6 +371,11 @@ below):: >>> Color.BLUE == 2 False +.. warning:: + + It is possible to reload modules -- if a reloaded module contains + enums, they will be recreated, and the new members may not + compare identical/equal to the original members. Allowed members and attributes of enumerations ---------------------------------------------- diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index 180399938208..34df5c511bf4 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -141,9 +141,8 @@ Module Contents :func:`global_enum` Modify the :class:`str() ` and :func:`repr` of an enum - to show its members as belonging to the module instead of its class. - Should only be used if the enum members will be exported to the - module global namespace. + to show its members as belonging to the module instead of its class, + and export the enum members to the global namespace. :func:`show_flag_values` @@ -170,6 +169,27 @@ Data Types final *enum*, as well as creating the enum members, properly handling duplicates, providing iteration over the enum class, etc. + .. method:: EnumType.__call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None) + + This method is called in two different ways: + + * to look up an existing member: + + :cls: The enum class being called. + :value: The value to lookup. + + * to use the ``cls`` enum to create a new enum (only if the existing enum + does not have any members): + + :cls: The enum class being called. + :value: The name of the new Enum to create. + :names: The names/values of the members for the new Enum. + :module: The name of the module the new Enum is created in. + :qualname: The actual location in the module where this Enum can be found. + :type: A mix-in type for the new Enum. + :start: The first integer value for the Enum (used by :class:`auto`). + :boundary: How to handle out-of-range values from bit operations (:class:`Flag` only). + .. method:: EnumType.__contains__(cls, member) Returns ``True`` if member belongs to the ``cls``:: @@ -262,26 +282,6 @@ Data Types names will also be removed from the completed enumeration. See :ref:`TimePeriod ` for an example. - .. method:: Enum.__call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None) - - This method is called in two different ways: - - * to look up an existing member: - - :cls: The enum class being called. - :value: The value to lookup. - - * to use the ``cls`` enum to create a new enum: - - :cls: The enum class being called. - :value: The name of the new Enum to create. - :names: The names/values of the members for the new Enum. - :module: The name of the module the new Enum is created in. - :qualname: The actual location in the module where this Enum can be found. - :type: A mix-in type for the new Enum. - :start: The first integer value for the Enum (used by :class:`auto`). - :boundary: How to handle out-of-range values from bit operations (:class:`Flag` only). - .. method:: Enum.__dir__(self) Returns ``['__class__', '__doc__', '__module__', 'name', 'value']`` and @@ -722,7 +722,6 @@ Data Types .. attribute:: EJECT Out-of-range values lose their *Flag* membership and revert to :class:`int`. - This is the default for :class:`IntFlag`:: >>> from enum import Flag, EJECT, auto >>> class EjectFlag(Flag, boundary=EJECT): @@ -734,8 +733,8 @@ Data Types .. attribute:: KEEP - Out-of-range values are kept, and the *Flag* membership is kept. This is - used for some stdlib flags:: + Out-of-range values are kept, and the *Flag* membership is kept. + This is the default for :class:`IntFlag`:: >>> from enum import Flag, KEEP, auto >>> class KeepFlag(Flag, boundary=KEEP): diff --git a/Lib/enum.py b/Lib/enum.py index 76575500e424..9138e50c3c6f 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1302,10 +1302,10 @@ def _reduce_ex_by_global_name(self, proto): class FlagBoundary(StrEnum): """ control how out of range values are handled - "strict" -> error is raised [default for Flag] - "conform" -> extra bits are discarded - "eject" -> lose flag status [default for IntFlag] - "keep" -> keep flag status and all bits + "strict" -> error is raised + "conform" -> extra bits are discarded [default for Flag] + "eject" -> lose flag status + "keep" -> keep flag status and all bits [default for IntFlag] """ STRICT = auto() CONFORM = auto() From webhook-mailer at python.org Mon Apr 3 18:44:12 2023 From: webhook-mailer at python.org (zooba) Date: Mon, 03 Apr 2023 22:44:12 -0000 Subject: [Python-checkins] gh-100062: Remove error code tables from _ssl and err_names_to_codes (GH-100063) Message-ID: https://github.com/python/cpython/commit/02f9920900551fd0281c8989d65521d4fce4ead1 commit: 02f9920900551fd0281c8989d65521d4fce4ead1 branch: main author: David Benjamin committer: zooba date: 2023-04-03T23:44:00+01:00 summary: gh-100062: Remove error code tables from _ssl and err_names_to_codes (GH-100063) Prior to https://github.com/python/cpython/pull/25300, the make_ssl_data.py script used various tables, exposed in _ssl, to update the error list. After that PR, this is no longer used. Moreover, the err_names_to_codes map isn't used at all. Clean those up. This gets them out of the way if, in the future, OpenSSL provides an API to do what the code here is doing directly. (https://github.com/openssl/openssl/issues/19848) files: M Modules/_ssl.c M Modules/_ssl.h diff --git a/Modules/_ssl.c b/Modules/_ssl.c index e0351a89e6a1..5f17cd502d45 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -5991,9 +5991,6 @@ sslmodule_init_errorcodes(PyObject *module) state->err_codes_to_names = PyDict_New(); if (state->err_codes_to_names == NULL) return -1; - state->err_names_to_codes = PyDict_New(); - if (state->err_names_to_codes == NULL) - return -1; state->lib_codes_to_names = PyDict_New(); if (state->lib_codes_to_names == NULL) return -1; @@ -6007,8 +6004,6 @@ sslmodule_init_errorcodes(PyObject *module) return -1; if (PyDict_SetItem(state->err_codes_to_names, key, mnemo)) return -1; - if (PyDict_SetItem(state->err_names_to_codes, mnemo, key)) - return -1; Py_DECREF(key); Py_DECREF(mnemo); errcode++; @@ -6028,13 +6023,6 @@ sslmodule_init_errorcodes(PyObject *module) libcode++; } - if (PyModule_AddObjectRef(module, "err_codes_to_names", state->err_codes_to_names)) - return -1; - if (PyModule_AddObjectRef(module, "err_names_to_codes", state->err_names_to_codes)) - return -1; - if (PyModule_AddObjectRef(module, "lib_codes_to_names", state->lib_codes_to_names)) - return -1; - return 0; } @@ -6189,7 +6177,6 @@ sslmodule_traverse(PyObject *m, visitproc visit, void *arg) Py_VISIT(state->PySSLSyscallErrorObject); Py_VISIT(state->PySSLEOFErrorObject); Py_VISIT(state->err_codes_to_names); - Py_VISIT(state->err_names_to_codes); Py_VISIT(state->lib_codes_to_names); Py_VISIT(state->Sock_Type); @@ -6214,7 +6201,6 @@ sslmodule_clear(PyObject *m) Py_CLEAR(state->PySSLSyscallErrorObject); Py_CLEAR(state->PySSLEOFErrorObject); Py_CLEAR(state->err_codes_to_names); - Py_CLEAR(state->err_names_to_codes); Py_CLEAR(state->lib_codes_to_names); Py_CLEAR(state->Sock_Type); Py_CLEAR(state->str_library); diff --git a/Modules/_ssl.h b/Modules/_ssl.h index d68ccdec5e88..c1da8b46b536 100644 --- a/Modules/_ssl.h +++ b/Modules/_ssl.h @@ -25,7 +25,6 @@ typedef struct { PyObject *PySSLEOFErrorObject; /* Error mappings */ PyObject *err_codes_to_names; - PyObject *err_names_to_codes; PyObject *lib_codes_to_names; /* socket type from module CAPI */ PyTypeObject *Sock_Type; From webhook-mailer at python.org Mon Apr 3 19:01:38 2023 From: webhook-mailer at python.org (miss-islington) Date: Mon, 03 Apr 2023 23:01:38 -0000 Subject: [Python-checkins] gh-102549: [Enum] fail enum creation when data type raises in __init__ (GH-103149) Message-ID: https://github.com/python/cpython/commit/5342f5e713e0cc45b6f226d2d053a8cde1b4d68e commit: 5342f5e713e0cc45b6f226d2d053a8cde1b4d68e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-03T16:01:31-07:00 summary: gh-102549: [Enum] fail enum creation when data type raises in __init__ (GH-103149) (cherry picked from commit 2a4d8c0a9e88f45047da640ce5a92b304d2d39b1) Co-authored-by: Ethan Furman files: A Misc/NEWS.d/next/Library/2023-03-27-19-21-51.gh-issue-102549.NQ6Nlv.rst M Lib/enum.py M Lib/test/test_enum.py diff --git a/Lib/enum.py b/Lib/enum.py index 9138e50c3c6f..13da287b34aa 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -250,23 +250,20 @@ def __set_name__(self, enum_class, member_name): args = (args, ) # wrap it one more time if not enum_class._use_args_: enum_member = enum_class._new_member_(enum_class) - if not hasattr(enum_member, '_value_'): + else: + enum_member = enum_class._new_member_(enum_class, *args) + if not hasattr(enum_member, '_value_'): + if enum_class._member_type_ is object: + enum_member._value_ = value + else: try: enum_member._value_ = enum_class._member_type_(*args) except Exception as exc: - enum_member._value_ = value - else: - enum_member = enum_class._new_member_(enum_class, *args) - if not hasattr(enum_member, '_value_'): - if enum_class._member_type_ is object: - enum_member._value_ = value - else: - try: - enum_member._value_ = enum_class._member_type_(*args) - except Exception as exc: - raise TypeError( - '_value_ not set in __new__, unable to create it' - ) from None + new_exc = TypeError( + '_value_ not set in __new__, unable to create it' + ) + new_exc.__cause__ = exc + raise new_exc value = enum_member._value_ enum_member._name_ = member_name enum_member.__objclass__ = enum_class diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index e9dae29d2687..09060733bc51 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -2787,6 +2787,26 @@ def __new__(cls, c): self.assertEqual(FlagFromChar.a, 158456325028528675187087900672) self.assertEqual(FlagFromChar.a|1, 158456325028528675187087900673) + def test_init_exception(self): + class Base: + def __init__(self, x): + raise ValueError("I don't like", x) + with self.assertRaises(TypeError): + class MyEnum(Base, enum.Enum): + A = 'a' + def __init__(self, y): + self.y = y + with self.assertRaises(ValueError): + class MyEnum(Base, enum.Enum): + A = 'a' + def __init__(self, y): + self.y = y + def __new__(cls, value): + member = Base.__new__(cls) + member._value_ = Base(value) + return member + + class TestOrder(unittest.TestCase): "test usage of the `_order_` attribute" diff --git a/Misc/NEWS.d/next/Library/2023-03-27-19-21-51.gh-issue-102549.NQ6Nlv.rst b/Misc/NEWS.d/next/Library/2023-03-27-19-21-51.gh-issue-102549.NQ6Nlv.rst new file mode 100644 index 000000000000..e4def038175b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-27-19-21-51.gh-issue-102549.NQ6Nlv.rst @@ -0,0 +1 @@ +Don't ignore exceptions in member type creation. From webhook-mailer at python.org Mon Apr 3 19:47:55 2023 From: webhook-mailer at python.org (brettcannon) Date: Mon, 03 Apr 2023 23:47:55 -0000 Subject: [Python-checkins] Specify more settings for the C extension of VS Code for dev containers (GH-103229) Message-ID: https://github.com/python/cpython/commit/c71756fa651e51041ac8b55776320e3297ba081d commit: c71756fa651e51041ac8b55776320e3297ba081d branch: main author: Brett Cannon committer: brettcannon date: 2023-04-03T16:47:48-07:00 summary: Specify more settings for the C extension of VS Code for dev containers (GH-103229) Should help with auto-complete. files: M .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index e3fb4c6c88f4..9fbaf7fddd85 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -37,10 +37,16 @@ // "ms-python.python" ], "settings": { + "C_Cpp.default.compilerPath": "/usr/bin/clang", "C_Cpp.default.cStandard": "c11", "C_Cpp.default.defines": [ + "CONFIG_64", "Py_BUILD_CORE" ], + "C_Cpp.default.includePath": [ + "${workspaceFolder}/*", + "${workspaceFolder}/Include/**" + ], // https://github.com/microsoft/vscode-cpptools/issues/10732 "C_Cpp.errorSquiggles": "disabled", "editor.insertSpaces": true, From webhook-mailer at python.org Mon Apr 3 20:47:49 2023 From: webhook-mailer at python.org (ethanfurman) Date: Tue, 04 Apr 2023 00:47:49 -0000 Subject: [Python-checkins] gh-103056: [Enum] use staticmethod decorator for _gnv_ (GH-103231) Message-ID: https://github.com/python/cpython/commit/810d365b5eb2cf3043957ca2971f6e7a7cd87d0d commit: 810d365b5eb2cf3043957ca2971f6e7a7cd87d0d branch: main author: Ethan Furman committer: ethanfurman date: 2023-04-03T17:47:40-07:00 summary: gh-103056: [Enum] use staticmethod decorator for _gnv_ (GH-103231) _gnv_ --> _generate_next_value_ files: M Doc/howto/enum.rst M Lib/enum.py diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst index fc8ea55069a9..38951ed7348f 100644 --- a/Doc/howto/enum.rst +++ b/Doc/howto/enum.rst @@ -284,6 +284,7 @@ The values are chosen by :func:`_generate_next_value_`, which can be overridden:: >>> class AutoName(Enum): + ... @staticmethod ... def _generate_next_value_(name, start, count, last_values): ... return name ... diff --git a/Lib/enum.py b/Lib/enum.py index 9d836c716d84..ec698d5fa3c3 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1146,6 +1146,7 @@ def __new__(cls, value): def __init__(self, *args, **kwds): pass + @staticmethod def _generate_next_value_(name, start, count, last_values): """ Generate the next value when not given. @@ -1288,6 +1289,7 @@ def __new__(cls, *values): member._value_ = value return member + @staticmethod def _generate_next_value_(name, start, count, last_values): """ Return the lower-cased version of the member name. @@ -1337,6 +1339,7 @@ def __reduce_ex__(self, proto): _numeric_repr_ = repr + @staticmethod def _generate_next_value_(name, start, count, last_values): """ Generate the next value when not given. From webhook-mailer at python.org Tue Apr 4 06:09:41 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Tue, 04 Apr 2023 10:09:41 -0000 Subject: [Python-checkins] gh-103092: Isolate `_pickle` module (#102982) Message-ID: https://github.com/python/cpython/commit/c00dcf0e381a090f7e905f887a98bbf63c88af5a commit: c00dcf0e381a090f7e905f887a98bbf63c88af5a branch: main author: Erlend E. Aasland committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-04-04T15:38:54+05:30 summary: gh-103092: Isolate `_pickle` module (#102982) Co-authored-by: Mohamed Koubaa Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: A Misc/NEWS.d/next/Core and Builtins/2020-07-04-09-04-41.bpo-1635741.ZsP31Y.rst M Lib/test/test_pickle.py M Modules/_pickle.c M Modules/clinic/_pickle.c.h M Tools/c-analyzer/cpython/globals-to-fix.tsv diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py index 80e7a4d23a4b..1a55da39bdc5 100644 --- a/Lib/test/test_pickle.py +++ b/Lib/test/test_pickle.py @@ -293,6 +293,34 @@ class CustomCPicklerClass(_pickle.Pickler, AbstractCustomPicklerClass): pass pickler_class = CustomCPicklerClass + @support.cpython_only + class HeapTypesTests(unittest.TestCase): + def setUp(self): + pickler = _pickle.Pickler(io.BytesIO()) + unpickler = _pickle.Unpickler(io.BytesIO()) + + self._types = ( + _pickle.Pickler, + _pickle.Unpickler, + type(pickler.memo), + type(unpickler.memo), + + # We cannot test the _pickle.Pdata; + # there's no way to get to it. + ) + + def test_have_gc(self): + import gc + for tp in self._types: + with self.subTest(tp=tp): + self.assertTrue(gc.is_tracked(tp)) + + def test_immutable(self): + for tp in self._types: + with self.subTest(tp=tp): + with self.assertRaisesRegex(TypeError, "immutable"): + tp.foo = "bar" + @support.cpython_only class SizeofTests(unittest.TestCase): check_sizeof = support.check_sizeof diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-07-04-09-04-41.bpo-1635741.ZsP31Y.rst b/Misc/NEWS.d/next/Core and Builtins/2020-07-04-09-04-41.bpo-1635741.ZsP31Y.rst new file mode 100644 index 000000000000..9f9c8121bea5 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-07-04-09-04-41.bpo-1635741.ZsP31Y.rst @@ -0,0 +1 @@ +Adapt :mod:`!_pickle` to :pep:`687`. Patch by Mohamed Koubaa and Erlend Aasland. diff --git a/Modules/_pickle.c b/Modules/_pickle.c index a26732af8ba2..360c7910f671 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -22,12 +22,12 @@ PyDoc_STRVAR(pickle_module_doc, /*[clinic input] module _pickle -class _pickle.Pickler "PicklerObject *" "&Pickler_Type" -class _pickle.PicklerMemoProxy "PicklerMemoProxyObject *" "&PicklerMemoProxyType" -class _pickle.Unpickler "UnpicklerObject *" "&Unpickler_Type" -class _pickle.UnpicklerMemoProxy "UnpicklerMemoProxyObject *" "&UnpicklerMemoProxyType" +class _pickle.Pickler "PicklerObject *" "" +class _pickle.PicklerMemoProxy "PicklerMemoProxyObject *" "" +class _pickle.Unpickler "UnpicklerObject *" "" +class _pickle.UnpicklerMemoProxy "UnpicklerMemoProxyObject *" "" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=4b3e113468a58e6c]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b6d7191ab6466cda]*/ /* Bump HIGHEST_PROTOCOL when new opcodes are added to the pickle protocol. Bump DEFAULT_PROTOCOL only when the oldest still supported version of Python @@ -192,24 +192,41 @@ typedef struct { /* functools.partial, used for implementing __newobj_ex__ with protocols 2 and 3 */ PyObject *partial; + + /* Types */ + PyTypeObject *Pickler_Type; + PyTypeObject *Unpickler_Type; + PyTypeObject *Pdata_Type; + PyTypeObject *PicklerMemoProxyType; + PyTypeObject *UnpicklerMemoProxyType; } PickleState; /* Forward declaration of the _pickle module definition. */ static struct PyModuleDef _picklemodule; /* Given a module object, get its per-module state. */ -static PickleState * +static inline PickleState * _Pickle_GetState(PyObject *module) { - return (PickleState *)_PyModule_GetState(module); + void *state = _PyModule_GetState(module); + assert(state != NULL); + return (PickleState *)state; +} + +static inline PickleState * +_Pickle_GetStateByClass(PyTypeObject *cls) +{ + void *state = _PyType_GetModuleState(cls); + assert(state != NULL); + return (PickleState *)state; } -/* Find the module instance imported in the currently running sub-interpreter - and get its state. */ -static PickleState * -_Pickle_GetGlobalState(void) +static inline PickleState * +_Pickle_FindStateByType(PyTypeObject *tp) { - return _Pickle_GetState(PyState_FindModule(&_picklemodule)); + PyObject *module = PyType_GetModuleByDef(tp, &_picklemodule); + assert(module != NULL); + return _Pickle_GetState(module); } /* Clear the given pickle module state. */ @@ -230,6 +247,11 @@ _Pickle_ClearState(PickleState *st) Py_CLEAR(st->codecs_encode); Py_CLEAR(st->getattr); Py_CLEAR(st->partial); + Py_CLEAR(st->Pickler_Type); + Py_CLEAR(st->Unpickler_Type); + Py_CLEAR(st->Pdata_Type); + Py_CLEAR(st->PicklerMemoProxyType); + Py_CLEAR(st->UnpicklerMemoProxyType); } /* Initialize the given pickle module state. */ @@ -439,39 +461,58 @@ typedef struct { Py_ssize_t allocated; /* number of slots in data allocated */ } Pdata; +static int +Pdata_traverse(Pdata *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + static void Pdata_dealloc(Pdata *self) { + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); Py_ssize_t i = Py_SIZE(self); while (--i >= 0) { Py_DECREF(self->data[i]); } PyMem_Free(self->data); - PyObject_Free(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); } -static PyTypeObject Pdata_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_pickle.Pdata", /*tp_name*/ - sizeof(Pdata), /*tp_basicsize*/ - sizeof(PyObject *), /*tp_itemsize*/ - (destructor)Pdata_dealloc, /*tp_dealloc*/ +static PyType_Slot pdata_slots[] = { + {Py_tp_dealloc, Pdata_dealloc}, + {Py_tp_traverse, Pdata_traverse}, + {0, NULL}, +}; + +static PyType_Spec pdata_spec = { + .name = "_pickle.Pdata", + .basicsize = sizeof(Pdata), + .itemsize = sizeof(PyObject *), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = pdata_slots, }; static PyObject * -Pdata_New(void) +Pdata_New(PickleState *state) { Pdata *self; - if (!(self = PyObject_New(Pdata, &Pdata_Type))) + if (!(self = PyObject_GC_New(Pdata, state->Pdata_Type))) return NULL; Py_SET_SIZE(self, 0); self->mark_set = 0; self->fence = 0; self->allocated = 8; self->data = PyMem_Malloc(self->allocated * sizeof(PyObject *)); - if (self->data) + if (self->data) { + PyObject_GC_Track(self); return (PyObject *)self; + } Py_DECREF(self); return PyErr_NoMemory(); } @@ -522,9 +563,8 @@ Pdata_grow(Pdata *self) } static int -Pdata_stack_underflow(Pdata *self) +Pdata_stack_underflow(PickleState *st, Pdata *self) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_SetString(st->UnpicklingError, self->mark_set ? "unexpected MARK found" : @@ -537,16 +577,16 @@ Pdata_stack_underflow(Pdata *self) * is raised and V is set to NULL. */ static PyObject * -Pdata_pop(Pdata *self) +Pdata_pop(PickleState *state, Pdata *self) { if (Py_SIZE(self) <= self->fence) { - Pdata_stack_underflow(self); + Pdata_stack_underflow(state, self); return NULL; } Py_SET_SIZE(self, Py_SIZE(self) - 1); return self->data[Py_SIZE(self)]; } -#define PDATA_POP(D, V) do { (V) = Pdata_pop((D)); } while (0) +#define PDATA_POP(S, D, V) do { (V) = Pdata_pop(S, (D)); } while (0) static int Pdata_push(Pdata *self, PyObject *obj) @@ -569,13 +609,13 @@ Pdata_push(Pdata *self, PyObject *obj) if (Pdata_push((D), (O)) < 0) return (ER); } while(0) static PyObject * -Pdata_poptuple(Pdata *self, Py_ssize_t start) +Pdata_poptuple(PickleState *state, Pdata *self, Py_ssize_t start) { PyObject *tuple; Py_ssize_t len, i, j; if (start < self->fence) { - Pdata_stack_underflow(self); + Pdata_stack_underflow(state, self); return NULL; } len = Py_SIZE(self) - start; @@ -710,10 +750,8 @@ typedef struct { } UnpicklerMemoProxyObject; /* Forward declarations */ -static int save(PicklerObject *, PyObject *, int); -static int save_reduce(PicklerObject *, PyObject *, PyObject *); -static PyTypeObject Pickler_Type; -static PyTypeObject Unpickler_Type; +static int save(PickleState *state, PicklerObject *, PyObject *, int); +static int save_reduce(PickleState *, PicklerObject *, PyObject *, PyObject *); #include "clinic/_pickle.c.h" @@ -1105,11 +1143,11 @@ _Pickler_Write(PicklerObject *self, const char *s, Py_ssize_t data_len) } static PicklerObject * -_Pickler_New(void) +_Pickler_New(PickleState *st) { PicklerObject *self; - self = PyObject_GC_New(PicklerObject, &Pickler_Type); + self = PyObject_GC_New(PicklerObject, st->Pickler_Type); if (self == NULL) return NULL; @@ -1220,9 +1258,8 @@ _Unpickler_SetStringInput(UnpicklerObject *self, PyObject *input) } static int -bad_readline(void) +bad_readline(PickleState *st) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_SetString(st->UnpicklingError, "pickle data was truncated"); return -1; } @@ -1317,13 +1354,12 @@ _Unpickler_ReadFromFile(UnpicklerObject *self, Py_ssize_t n) /* Don't call it directly: use _Unpickler_Read() */ static Py_ssize_t -_Unpickler_ReadImpl(UnpicklerObject *self, char **s, Py_ssize_t n) +_Unpickler_ReadImpl(UnpicklerObject *self, PickleState *st, char **s, Py_ssize_t n) { Py_ssize_t num_read; *s = NULL; if (self->next_read_idx > PY_SSIZE_T_MAX - n) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_SetString(st->UnpicklingError, "read would overflow (invalid bytecode)"); return -1; @@ -1333,14 +1369,14 @@ _Unpickler_ReadImpl(UnpicklerObject *self, char **s, Py_ssize_t n) assert(self->next_read_idx + n > self->input_len); if (!self->read) - return bad_readline(); + return bad_readline(st); /* Extend the buffer to satisfy desired size */ num_read = _Unpickler_ReadFromFile(self, n); if (num_read < 0) return -1; if (num_read < n) - return bad_readline(); + return bad_readline(st); *s = self->input_buffer; self->next_read_idx = n; return n; @@ -1355,7 +1391,8 @@ _Unpickler_ReadImpl(UnpicklerObject *self, char **s, Py_ssize_t n) * _Unpickler_Read() is recommended in most cases. */ static Py_ssize_t -_Unpickler_ReadInto(UnpicklerObject *self, char *buf, Py_ssize_t n) +_Unpickler_ReadInto(PickleState *state, UnpicklerObject *self, char *buf, + Py_ssize_t n) { assert(n != READ_WHOLE_LINE); @@ -1376,7 +1413,7 @@ _Unpickler_ReadInto(UnpicklerObject *self, char *buf, Py_ssize_t n) /* Read from file */ if (!self->read) { /* We're unpickling memory, this means the input is truncated */ - return bad_readline(); + return bad_readline(state); } if (_Unpickler_SkipConsumed(self) < 0) { return -1; @@ -1403,7 +1440,7 @@ _Unpickler_ReadInto(UnpicklerObject *self, char *buf, Py_ssize_t n) Py_ssize_t read_size = PyBytes_GET_SIZE(data); if (read_size < n) { Py_DECREF(data); - return bad_readline(); + return bad_readline(state); } memcpy(buf, PyBytes_AS_STRING(data), n); Py_DECREF(data); @@ -1430,7 +1467,7 @@ _Unpickler_ReadInto(UnpicklerObject *self, char *buf, Py_ssize_t n) return -1; } if (read_size < n) { - return bad_readline(); + return bad_readline(state); } return n; } @@ -1448,12 +1485,12 @@ _Unpickler_ReadInto(UnpicklerObject *self, char *buf, Py_ssize_t n) Returns -1 (with an exception set) on failure. On success, return the number of chars read. */ -#define _Unpickler_Read(self, s, n) \ +#define _Unpickler_Read(self, state, s, n) \ (((n) <= (self)->input_len - (self)->next_read_idx) \ ? (*(s) = (self)->input_buffer + (self)->next_read_idx, \ (self)->next_read_idx += (n), \ (n)) \ - : _Unpickler_ReadImpl(self, (s), (n))) + : _Unpickler_ReadImpl(self, state, (s), (n))) static Py_ssize_t _Unpickler_CopyLine(UnpicklerObject *self, char *line, Py_ssize_t len, @@ -1477,7 +1514,7 @@ _Unpickler_CopyLine(UnpicklerObject *self, char *line, Py_ssize_t len, Returns the number of chars read, or -1 on failure. */ static Py_ssize_t -_Unpickler_Readline(UnpicklerObject *self, char **result) +_Unpickler_Readline(PickleState *state, UnpicklerObject *self, char **result) { Py_ssize_t i, num_read; @@ -1490,13 +1527,13 @@ _Unpickler_Readline(UnpicklerObject *self, char **result) } } if (!self->read) - return bad_readline(); + return bad_readline(state); num_read = _Unpickler_ReadFromFile(self, READ_WHOLE_LINE); if (num_read < 0) return -1; if (num_read == 0 || self->input_buffer[num_read - 1] != '\n') - return bad_readline(); + return bad_readline(state); self->next_read_idx = num_read; return _Unpickler_CopyLine(self, self->input_buffer, num_read, result); } @@ -1586,11 +1623,12 @@ _Unpickler_MemoCleanup(UnpicklerObject *self) } static UnpicklerObject * -_Unpickler_New(void) +_Unpickler_New(PyObject *module) { UnpicklerObject *self; + PickleState *st = _Pickle_GetState(module); - self = PyObject_GC_New(UnpicklerObject, &Unpickler_Type); + self = PyObject_GC_New(UnpicklerObject, st->Unpickler_Type); if (self == NULL) return NULL; @@ -1616,7 +1654,7 @@ _Unpickler_New(void) self->memo_size = 32; self->memo_len = 0; self->memo = _Unpickler_NewMemo(self->memo_size); - self->stack = (Pdata *)Pdata_New(); + self->stack = (Pdata *)Pdata_New(st); if (self->memo == NULL || self->stack == NULL) { Py_DECREF(self); @@ -1695,7 +1733,7 @@ _Unpickler_SetBuffers(UnpicklerObject *self, PyObject *buffers) /* Generate a GET opcode for an object stored in the memo. */ static int -memo_get(PicklerObject *self, PyObject *key) +memo_get(PickleState *st, PicklerObject *self, PyObject *key) { Py_ssize_t *value; char pdata[30]; @@ -1728,7 +1766,6 @@ memo_get(PicklerObject *self, PyObject *key) len = 5; } else { /* unlikely */ - PickleState *st = _Pickle_GetGlobalState(); PyErr_SetString(st->PicklingError, "memo id too large for LONG_BINGET"); return -1; @@ -1744,7 +1781,7 @@ memo_get(PicklerObject *self, PyObject *key) /* Store an object in the memo, assign it a new unique ID based on the number of objects currently stored in the memo and generate a PUT opcode. */ static int -memo_put(PicklerObject *self, PyObject *obj) +memo_put(PickleState *st, PicklerObject *self, PyObject *obj) { char pdata[30]; Py_ssize_t len; @@ -1785,7 +1822,6 @@ memo_put(PicklerObject *self, PyObject *obj) len = 5; } else { /* unlikely */ - PickleState *st = _Pickle_GetGlobalState(); PyErr_SetString(st->PicklingError, "memo id too large for LONG_BINPUT"); return -1; @@ -2338,8 +2374,8 @@ _Pickler_write_bytes(PicklerObject *self, } static int -_save_bytes_data(PicklerObject *self, PyObject *obj, const char *data, - Py_ssize_t size) +_save_bytes_data(PickleState *st, PicklerObject *self, PyObject *obj, + const char *data, Py_ssize_t size) { assert(self->proto >= 3); @@ -2378,7 +2414,7 @@ _save_bytes_data(PicklerObject *self, PyObject *obj, const char *data, return -1; } - if (memo_put(self, obj) < 0) { + if (memo_put(st, self, obj) < 0) { return -1; } @@ -2386,7 +2422,7 @@ _save_bytes_data(PicklerObject *self, PyObject *obj, const char *data, } static int -save_bytes(PicklerObject *self, PyObject *obj) +save_bytes(PickleState *st, PicklerObject *self, PyObject *obj) { if (self->proto < 3) { /* Older pickle protocols do not have an opcode for pickling bytes @@ -2407,7 +2443,6 @@ save_bytes(PicklerObject *self, PyObject *obj) reduce_value = Py_BuildValue("(O())", (PyObject*)&PyBytes_Type); } else { - PickleState *st = _Pickle_GetGlobalState(); PyObject *unicode_str = PyUnicode_DecodeLatin1(PyBytes_AS_STRING(obj), PyBytes_GET_SIZE(obj), @@ -2425,19 +2460,19 @@ save_bytes(PicklerObject *self, PyObject *obj) return -1; /* save_reduce() will memoize the object automatically. */ - status = save_reduce(self, reduce_value, obj); + status = save_reduce(st, self, reduce_value, obj); Py_DECREF(reduce_value); return status; } else { - return _save_bytes_data(self, obj, PyBytes_AS_STRING(obj), + return _save_bytes_data(st, self, obj, PyBytes_AS_STRING(obj), PyBytes_GET_SIZE(obj)); } } static int -_save_bytearray_data(PicklerObject *self, PyObject *obj, const char *data, - Py_ssize_t size) +_save_bytearray_data(PickleState *state, PicklerObject *self, PyObject *obj, + const char *data, Py_ssize_t size) { assert(self->proto >= 5); @@ -2455,7 +2490,7 @@ _save_bytearray_data(PicklerObject *self, PyObject *obj, const char *data, return -1; } - if (memo_put(self, obj) < 0) { + if (memo_put(state, self, obj) < 0) { return -1; } @@ -2463,7 +2498,7 @@ _save_bytearray_data(PicklerObject *self, PyObject *obj, const char *data, } static int -save_bytearray(PicklerObject *self, PyObject *obj) +save_bytearray(PickleState *state, PicklerObject *self, PyObject *obj) { if (self->proto < 5) { /* Older pickle protocols do not have an opcode for pickling @@ -2488,21 +2523,21 @@ save_bytearray(PicklerObject *self, PyObject *obj) return -1; /* save_reduce() will memoize the object automatically. */ - status = save_reduce(self, reduce_value, obj); + status = save_reduce(state, self, reduce_value, obj); Py_DECREF(reduce_value); return status; } else { - return _save_bytearray_data(self, obj, PyByteArray_AS_STRING(obj), + return _save_bytearray_data(state, self, obj, + PyByteArray_AS_STRING(obj), PyByteArray_GET_SIZE(obj)); } } static int -save_picklebuffer(PicklerObject *self, PyObject *obj) +save_picklebuffer(PickleState *st, PicklerObject *self, PyObject *obj) { if (self->proto < 5) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_SetString(st->PicklingError, "PickleBuffer can only pickled with protocol >= 5"); return -1; @@ -2512,7 +2547,6 @@ save_picklebuffer(PicklerObject *self, PyObject *obj) return -1; } if (view->suboffsets != NULL || !PyBuffer_IsContiguous(view, 'A')) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_SetString(st->PicklingError, "PickleBuffer can not be pickled when " "pointing to a non-contiguous buffer"); @@ -2533,11 +2567,11 @@ save_picklebuffer(PicklerObject *self, PyObject *obj) if (in_band) { /* Write data in-band */ if (view->readonly) { - return _save_bytes_data(self, obj, (const char*) view->buf, + return _save_bytes_data(st, self, obj, (const char *)view->buf, view->len); } else { - return _save_bytearray_data(self, obj, (const char*) view->buf, + return _save_bytearray_data(st, self, obj, (const char *)view->buf, view->len); } } @@ -2692,7 +2726,7 @@ write_unicode_binary(PicklerObject *self, PyObject *obj) } static int -save_unicode(PicklerObject *self, PyObject *obj) +save_unicode(PickleState *state, PicklerObject *self, PyObject *obj) { if (self->bin) { if (write_unicode_binary(self, obj) < 0) @@ -2722,7 +2756,7 @@ save_unicode(PicklerObject *self, PyObject *obj) if (_Pickler_Write(self, "\n", 1) < 0) return -1; } - if (memo_put(self, obj) < 0) + if (memo_put(state, self, obj) < 0) return -1; return 0; @@ -2730,7 +2764,8 @@ save_unicode(PicklerObject *self, PyObject *obj) /* A helper for save_tuple. Push the len elements in tuple t on the stack. */ static int -store_tuple_elements(PicklerObject *self, PyObject *t, Py_ssize_t len) +store_tuple_elements(PickleState *state, PicklerObject *self, PyObject *t, + Py_ssize_t len) { Py_ssize_t i; @@ -2741,7 +2776,7 @@ store_tuple_elements(PicklerObject *self, PyObject *t, Py_ssize_t len) if (element == NULL) return -1; - if (save(self, element, 0) < 0) + if (save(state, self, element, 0) < 0) return -1; } @@ -2755,7 +2790,7 @@ store_tuple_elements(PicklerObject *self, PyObject *t, Py_ssize_t len) * magic so that it works in all cases. IOW, this is a long routine. */ static int -save_tuple(PicklerObject *self, PyObject *obj) +save_tuple(PickleState *state, PicklerObject *self, PyObject *obj) { Py_ssize_t len, i; @@ -2792,7 +2827,7 @@ save_tuple(PicklerObject *self, PyObject *obj) */ if (len <= 3 && self->proto >= 2) { /* Use TUPLE{1,2,3} opcodes. */ - if (store_tuple_elements(self, obj, len) < 0) + if (store_tuple_elements(state, self, obj, len) < 0) return -1; if (PyMemoTable_Get(self->memo, obj)) { @@ -2801,7 +2836,7 @@ save_tuple(PicklerObject *self, PyObject *obj) if (_Pickler_Write(self, &pop_op, 1) < 0) return -1; /* fetch from memo */ - if (memo_get(self, obj) < 0) + if (memo_get(state, self, obj) < 0) return -1; return 0; @@ -2819,7 +2854,7 @@ save_tuple(PicklerObject *self, PyObject *obj) if (_Pickler_Write(self, &mark_op, 1) < 0) return -1; - if (store_tuple_elements(self, obj, len) < 0) + if (store_tuple_elements(state, self, obj, len) < 0) return -1; if (PyMemoTable_Get(self->memo, obj)) { @@ -2837,7 +2872,7 @@ save_tuple(PicklerObject *self, PyObject *obj) return -1; } /* fetch from memo */ - if (memo_get(self, obj) < 0) + if (memo_get(state, self, obj) < 0) return -1; return 0; @@ -2848,7 +2883,7 @@ save_tuple(PicklerObject *self, PyObject *obj) } memoize: - if (memo_put(self, obj) < 0) + if (memo_put(state, self, obj) < 0) return -1; return 0; @@ -2861,7 +2896,7 @@ save_tuple(PicklerObject *self, PyObject *obj) * Returns 0 on success, <0 on error. */ static int -batch_list(PicklerObject *self, PyObject *iter) +batch_list(PickleState *state, PicklerObject *self, PyObject *iter) { PyObject *obj = NULL; PyObject *firstitem = NULL; @@ -2887,7 +2922,7 @@ batch_list(PicklerObject *self, PyObject *iter) return -1; break; } - i = save(self, obj, 0); + i = save(state, self, obj, 0); Py_DECREF(obj); if (i < 0) return -1; @@ -2916,7 +2951,7 @@ batch_list(PicklerObject *self, PyObject *iter) goto error; /* Only one item to write */ - if (save(self, firstitem, 0) < 0) + if (save(state, self, firstitem, 0) < 0) goto error; if (_Pickler_Write(self, &append_op, 1) < 0) goto error; @@ -2930,14 +2965,14 @@ batch_list(PicklerObject *self, PyObject *iter) if (_Pickler_Write(self, &mark_op, 1) < 0) goto error; - if (save(self, firstitem, 0) < 0) + if (save(state, self, firstitem, 0) < 0) goto error; Py_CLEAR(firstitem); n = 1; /* Fetch and save up to BATCHSIZE items */ while (obj) { - if (save(self, obj, 0) < 0) + if (save(state, self, obj, 0) < 0) goto error; Py_CLEAR(obj); n += 1; @@ -2977,7 +3012,7 @@ batch_list(PicklerObject *self, PyObject *iter) * Note that this only works for protocols > 0. */ static int -batch_list_exact(PicklerObject *self, PyObject *obj) +batch_list_exact(PickleState *state, PicklerObject *self, PyObject *obj) { PyObject *item = NULL; Py_ssize_t this_batch, total; @@ -2993,7 +3028,7 @@ batch_list_exact(PicklerObject *self, PyObject *obj) if (PyList_GET_SIZE(obj) == 1) { item = PyList_GET_ITEM(obj, 0); Py_INCREF(item); - int err = save(self, item, 0); + int err = save(state, self, item, 0); Py_DECREF(item); if (err < 0) return -1; @@ -3011,7 +3046,7 @@ batch_list_exact(PicklerObject *self, PyObject *obj) while (total < PyList_GET_SIZE(obj)) { item = PyList_GET_ITEM(obj, total); Py_INCREF(item); - int err = save(self, item, 0); + int err = save(state, self, item, 0); Py_DECREF(item); if (err < 0) return -1; @@ -3028,7 +3063,7 @@ batch_list_exact(PicklerObject *self, PyObject *obj) } static int -save_list(PicklerObject *self, PyObject *obj) +save_list(PickleState *state, PicklerObject *self, PyObject *obj) { char header[3]; Py_ssize_t len; @@ -3055,7 +3090,7 @@ save_list(PicklerObject *self, PyObject *obj) if ((len = PyList_Size(obj)) < 0) goto error; - if (memo_put(self, obj) < 0) + if (memo_put(state, self, obj) < 0) goto error; if (len != 0) { @@ -3063,7 +3098,7 @@ save_list(PicklerObject *self, PyObject *obj) if (PyList_CheckExact(obj) && self->proto > 0) { if (_Py_EnterRecursiveCall(" while pickling an object")) goto error; - status = batch_list_exact(self, obj); + status = batch_list_exact(state, self, obj); _Py_LeaveRecursiveCall(); } else { PyObject *iter = PyObject_GetIter(obj); @@ -3074,7 +3109,7 @@ save_list(PicklerObject *self, PyObject *obj) Py_DECREF(iter); goto error; } - status = batch_list(self, iter); + status = batch_list(state, self, iter); _Py_LeaveRecursiveCall(); Py_DECREF(iter); } @@ -3102,7 +3137,7 @@ save_list(PicklerObject *self, PyObject *obj) * ugly to bear. */ static int -batch_dict(PicklerObject *self, PyObject *iter) +batch_dict(PickleState *state, PicklerObject *self, PyObject *iter) { PyObject *obj = NULL; PyObject *firstitem = NULL; @@ -3128,9 +3163,9 @@ batch_dict(PicklerObject *self, PyObject *iter) "iterator must return 2-tuples"); return -1; } - i = save(self, PyTuple_GET_ITEM(obj, 0), 0); + i = save(state, self, PyTuple_GET_ITEM(obj, 0), 0); if (i >= 0) - i = save(self, PyTuple_GET_ITEM(obj, 1), 0); + i = save(state, self, PyTuple_GET_ITEM(obj, 1), 0); Py_DECREF(obj); if (i < 0) return -1; @@ -3164,9 +3199,9 @@ batch_dict(PicklerObject *self, PyObject *iter) goto error; /* Only one item to write */ - if (save(self, PyTuple_GET_ITEM(firstitem, 0), 0) < 0) + if (save(state, self, PyTuple_GET_ITEM(firstitem, 0), 0) < 0) goto error; - if (save(self, PyTuple_GET_ITEM(firstitem, 1), 0) < 0) + if (save(state, self, PyTuple_GET_ITEM(firstitem, 1), 0) < 0) goto error; if (_Pickler_Write(self, &setitem_op, 1) < 0) goto error; @@ -3180,9 +3215,9 @@ batch_dict(PicklerObject *self, PyObject *iter) if (_Pickler_Write(self, &mark_op, 1) < 0) goto error; - if (save(self, PyTuple_GET_ITEM(firstitem, 0), 0) < 0) + if (save(state, self, PyTuple_GET_ITEM(firstitem, 0), 0) < 0) goto error; - if (save(self, PyTuple_GET_ITEM(firstitem, 1), 0) < 0) + if (save(state, self, PyTuple_GET_ITEM(firstitem, 1), 0) < 0) goto error; Py_CLEAR(firstitem); n = 1; @@ -3194,8 +3229,8 @@ batch_dict(PicklerObject *self, PyObject *iter) "iterator must return 2-tuples"); goto error; } - if (save(self, PyTuple_GET_ITEM(obj, 0), 0) < 0 || - save(self, PyTuple_GET_ITEM(obj, 1), 0) < 0) + if (save(state, self, PyTuple_GET_ITEM(obj, 0), 0) < 0 || + save(state, self, PyTuple_GET_ITEM(obj, 1), 0) < 0) goto error; Py_CLEAR(obj); n += 1; @@ -3233,7 +3268,7 @@ batch_dict(PicklerObject *self, PyObject *iter) * Note that this currently doesn't work for protocol 0. */ static int -batch_dict_exact(PicklerObject *self, PyObject *obj) +batch_dict_exact(PickleState *state, PicklerObject *self, PyObject *obj) { PyObject *key = NULL, *value = NULL; int i; @@ -3253,10 +3288,10 @@ batch_dict_exact(PicklerObject *self, PyObject *obj) PyDict_Next(obj, &ppos, &key, &value); Py_INCREF(key); Py_INCREF(value); - if (save(self, key, 0) < 0) { + if (save(state, self, key, 0) < 0) { goto error; } - if (save(self, value, 0) < 0) { + if (save(state, self, value, 0) < 0) { goto error; } Py_CLEAR(key); @@ -3274,10 +3309,10 @@ batch_dict_exact(PicklerObject *self, PyObject *obj) while (PyDict_Next(obj, &ppos, &key, &value)) { Py_INCREF(key); Py_INCREF(value); - if (save(self, key, 0) < 0) { + if (save(state, self, key, 0) < 0) { goto error; } - if (save(self, value, 0) < 0) { + if (save(state, self, value, 0) < 0) { goto error; } Py_CLEAR(key); @@ -3303,7 +3338,7 @@ batch_dict_exact(PicklerObject *self, PyObject *obj) } static int -save_dict(PicklerObject *self, PyObject *obj) +save_dict(PickleState *state, PicklerObject *self, PyObject *obj) { PyObject *items, *iter; char header[3]; @@ -3328,7 +3363,7 @@ save_dict(PicklerObject *self, PyObject *obj) if (_Pickler_Write(self, header, len) < 0) goto error; - if (memo_put(self, obj) < 0) + if (memo_put(state, self, obj) < 0) goto error; if (PyDict_GET_SIZE(obj)) { @@ -3338,7 +3373,7 @@ save_dict(PicklerObject *self, PyObject *obj) not a dict subclass. */ if (_Py_EnterRecursiveCall(" while pickling an object")) goto error; - status = batch_dict_exact(self, obj); + status = batch_dict_exact(state, self, obj); _Py_LeaveRecursiveCall(); } else { items = PyObject_CallMethodNoArgs(obj, &_Py_ID(items)); @@ -3352,7 +3387,7 @@ save_dict(PicklerObject *self, PyObject *obj) Py_DECREF(iter); goto error; } - status = batch_dict(self, iter); + status = batch_dict(state, self, iter); _Py_LeaveRecursiveCall(); Py_DECREF(iter); } @@ -3370,7 +3405,7 @@ save_dict(PicklerObject *self, PyObject *obj) } static int -save_set(PicklerObject *self, PyObject *obj) +save_set(PickleState *state, PicklerObject *self, PyObject *obj) { PyObject *item; int i; @@ -3396,7 +3431,7 @@ save_set(PicklerObject *self, PyObject *obj) return -1; } /* save_reduce() will memoize the object automatically. */ - status = save_reduce(self, reduce_value, obj); + status = save_reduce(state, self, reduce_value, obj); Py_DECREF(reduce_value); return status; } @@ -3404,7 +3439,7 @@ save_set(PicklerObject *self, PyObject *obj) if (_Pickler_Write(self, &empty_set_op, 1) < 0) return -1; - if (memo_put(self, obj) < 0) + if (memo_put(state, self, obj) < 0) return -1; set_size = PySet_GET_SIZE(obj); @@ -3418,7 +3453,7 @@ save_set(PicklerObject *self, PyObject *obj) return -1; while (_PySet_NextEntry(obj, &ppos, &item, &hash)) { Py_INCREF(item); - int err = save(self, item, 0); + int err = save(state, self, item, 0); Py_CLEAR(item); if (err < 0) return -1; @@ -3439,7 +3474,7 @@ save_set(PicklerObject *self, PyObject *obj) } static int -save_frozenset(PicklerObject *self, PyObject *obj) +save_frozenset(PickleState *state, PicklerObject *self, PyObject *obj) { PyObject *iter; @@ -3465,7 +3500,7 @@ save_frozenset(PicklerObject *self, PyObject *obj) return -1; } /* save_reduce() will memoize the object automatically. */ - status = save_reduce(self, reduce_value, obj); + status = save_reduce(state, self, reduce_value, obj); Py_DECREF(reduce_value); return status; } @@ -3488,7 +3523,7 @@ save_frozenset(PicklerObject *self, PyObject *obj) } break; } - if (save(self, item, 0) < 0) { + if (save(state, self, item, 0) < 0) { Py_DECREF(item); Py_DECREF(iter); return -1; @@ -3505,25 +3540,24 @@ save_frozenset(PicklerObject *self, PyObject *obj) if (_Pickler_Write(self, &pop_mark_op, 1) < 0) return -1; - if (memo_get(self, obj) < 0) + if (memo_get(state, self, obj) < 0) return -1; return 0; } if (_Pickler_Write(self, &frozenset_op, 1) < 0) return -1; - if (memo_put(self, obj) < 0) + if (memo_put(state, self, obj) < 0) return -1; return 0; } static int -fix_imports(PyObject **module_name, PyObject **global_name) +fix_imports(PickleState *st, PyObject **module_name, PyObject **global_name) { PyObject *key; PyObject *item; - PickleState *st = _Pickle_GetGlobalState(); key = PyTuple_Pack(2, *module_name, *global_name); if (key == NULL) @@ -3582,7 +3616,8 @@ fix_imports(PyObject **module_name, PyObject **global_name) } static int -save_global(PicklerObject *self, PyObject *obj, PyObject *name) +save_global(PickleState *st, PicklerObject *self, PyObject *obj, + PyObject *name) { PyObject *global_name = NULL; PyObject *module_name = NULL; @@ -3591,7 +3626,6 @@ save_global(PicklerObject *self, PyObject *obj, PyObject *name) PyObject *dotted_path = NULL; PyObject *lastname = NULL; PyObject *cls; - PickleState *st = _Pickle_GetGlobalState(); int status = 0; const char global_op = GLOBAL; @@ -3727,21 +3761,20 @@ save_global(PicklerObject *self, PyObject *obj, PyObject *name) if (self->proto >= 4) { const char stack_global_op = STACK_GLOBAL; - if (save(self, module_name, 0) < 0) + if (save(st, self, module_name, 0) < 0) goto error; - if (save(self, global_name, 0) < 0) + if (save(st, self, global_name, 0) < 0) goto error; if (_Pickler_Write(self, &stack_global_op, 1) < 0) goto error; } else if (parent != module) { - PickleState *st = _Pickle_GetGlobalState(); PyObject *reduce_value = Py_BuildValue("(O(OO))", st->getattr, parent, lastname); if (reduce_value == NULL) goto error; - status = save_reduce(self, reduce_value, NULL); + status = save_reduce(st, self, reduce_value, NULL); Py_DECREF(reduce_value); if (status < 0) goto error; @@ -3759,7 +3792,7 @@ save_global(PicklerObject *self, PyObject *obj, PyObject *name) /* For protocol < 3 and if the user didn't request against doing so, we convert module names to the old 2.x module names. */ if (self->proto < 3 && self->fix_imports) { - if (fix_imports(&module_name, &global_name) < 0) { + if (fix_imports(st, &module_name, &global_name) < 0) { goto error; } } @@ -3813,7 +3846,7 @@ save_global(PicklerObject *self, PyObject *obj, PyObject *name) goto error; } /* Memoize the object. */ - if (memo_put(self, obj) < 0) + if (memo_put(st, self, obj) < 0) goto error; } @@ -3832,7 +3865,8 @@ save_global(PicklerObject *self, PyObject *obj, PyObject *name) } static int -save_singleton_type(PicklerObject *self, PyObject *obj, PyObject *singleton) +save_singleton_type(PickleState *state, PicklerObject *self, PyObject *obj, + PyObject *singleton) { PyObject *reduce_value; int status; @@ -3841,28 +3875,28 @@ save_singleton_type(PicklerObject *self, PyObject *obj, PyObject *singleton) if (reduce_value == NULL) { return -1; } - status = save_reduce(self, reduce_value, obj); + status = save_reduce(state, self, reduce_value, obj); Py_DECREF(reduce_value); return status; } static int -save_type(PicklerObject *self, PyObject *obj) +save_type(PickleState *state, PicklerObject *self, PyObject *obj) { if (obj == (PyObject *)&_PyNone_Type) { - return save_singleton_type(self, obj, Py_None); + return save_singleton_type(state, self, obj, Py_None); } else if (obj == (PyObject *)&PyEllipsis_Type) { - return save_singleton_type(self, obj, Py_Ellipsis); + return save_singleton_type(state, self, obj, Py_Ellipsis); } else if (obj == (PyObject *)&_PyNotImplemented_Type) { - return save_singleton_type(self, obj, Py_NotImplemented); + return save_singleton_type(state, self, obj, Py_NotImplemented); } - return save_global(self, obj, NULL); + return save_global(state, self, obj, NULL); } static int -save_pers(PicklerObject *self, PyObject *obj) +save_pers(PickleState *state, PicklerObject *self, PyObject *obj) { PyObject *pid = NULL; int status = 0; @@ -3876,7 +3910,7 @@ save_pers(PicklerObject *self, PyObject *obj) if (pid != Py_None) { if (self->bin) { - if (save(self, pid, 1) < 0 || + if (save(state, self, pid, 1) < 0 || _Pickler_Write(self, &binpersid_op, 1) < 0) goto error; } @@ -3890,7 +3924,7 @@ save_pers(PicklerObject *self, PyObject *obj) /* XXX: Should it check whether the pid contains embedded newlines? */ if (!PyUnicode_IS_ASCII(pid_str)) { - PyErr_SetString(_Pickle_GetGlobalState()->PicklingError, + PyErr_SetString(state->PicklingError, "persistent IDs in protocol 0 must be " "ASCII strings"); Py_DECREF(pid_str); @@ -3933,7 +3967,8 @@ get_class(PyObject *obj) * appropriate __reduce__ method for obj. */ static int -save_reduce(PicklerObject *self, PyObject *args, PyObject *obj) +save_reduce(PickleState *st, PicklerObject *self, PyObject *args, + PyObject *obj) { PyObject *callable; PyObject *argtup; @@ -3941,7 +3976,6 @@ save_reduce(PicklerObject *self, PyObject *args, PyObject *obj) PyObject *listitems = Py_None; PyObject *dictitems = Py_None; PyObject *state_setter = Py_None; - PickleState *st = _Pickle_GetGlobalState(); Py_ssize_t size; int use_newobj = 0, use_newobj_ex = 0; @@ -4053,9 +4087,9 @@ save_reduce(PicklerObject *self, PyObject *args, PyObject *obj) } if (self->proto >= 4) { - if (save(self, cls, 0) < 0 || - save(self, args, 0) < 0 || - save(self, kwargs, 0) < 0 || + if (save(st, self, cls, 0) < 0 || + save(st, self, args, 0) < 0 || + save(st, self, kwargs, 0) < 0 || _Pickler_Write(self, &newobj_ex_op, 1) < 0) { return -1; } @@ -4092,8 +4126,8 @@ save_reduce(PicklerObject *self, PyObject *args, PyObject *obj) return -1; } - if (save(self, callable, 0) < 0 || - save(self, newargs, 0) < 0 || + if (save(st, self, callable, 0) < 0 || + save(st, self, newargs, 0) < 0 || _Pickler_Write(self, &reduce_op, 1) < 0) { Py_DECREF(newargs); Py_DECREF(callable); @@ -4163,14 +4197,15 @@ save_reduce(PicklerObject *self, PyObject *args, PyObject *obj) function. */ /* Save the class and its __new__ arguments. */ - if (save(self, cls, 0) < 0) + if (save(st, self, cls, 0) < 0) { return -1; + } newargtup = PyTuple_GetSlice(argtup, 1, PyTuple_GET_SIZE(argtup)); if (newargtup == NULL) return -1; - p = save(self, newargtup, 0); + p = save(st, self, newargtup, 0); Py_DECREF(newargtup); if (p < 0) return -1; @@ -4180,8 +4215,8 @@ save_reduce(PicklerObject *self, PyObject *args, PyObject *obj) return -1; } else { /* Not using NEWOBJ. */ - if (save(self, callable, 0) < 0 || - save(self, argtup, 0) < 0 || + if (save(st, self, callable, 0) < 0 || + save(st, self, argtup, 0) < 0 || _Pickler_Write(self, &reduce_op, 1) < 0) return -1; } @@ -4199,24 +4234,24 @@ save_reduce(PicklerObject *self, PyObject *args, PyObject *obj) if (_Pickler_Write(self, &pop_op, 1) < 0) return -1; - if (memo_get(self, obj) < 0) + if (memo_get(st, self, obj) < 0) return -1; return 0; } - else if (memo_put(self, obj) < 0) + else if (memo_put(st, self, obj) < 0) return -1; } - if (listitems && batch_list(self, listitems) < 0) + if (listitems && batch_list(st, self, listitems) < 0) return -1; - if (dictitems && batch_dict(self, dictitems) < 0) + if (dictitems && batch_dict(st, self, dictitems) < 0) return -1; if (state) { if (state_setter == NULL) { - if (save(self, state, 0) < 0 || + if (save(st, self, state, 0) < 0 || _Pickler_Write(self, &build_op, 1) < 0) return -1; } @@ -4233,8 +4268,8 @@ save_reduce(PicklerObject *self, PyObject *args, PyObject *obj) const char tupletwo_op = TUPLE2; const char pop_op = POP; - if (save(self, state_setter, 0) < 0 || - save(self, obj, 0) < 0 || save(self, state, 0) < 0 || + if (save(st, self, state_setter, 0) < 0 || + save(st, self, obj, 0) < 0 || save(st, self, state, 0) < 0 || _Pickler_Write(self, &tupletwo_op, 1) < 0 || _Pickler_Write(self, &reduce_op, 1) < 0 || _Pickler_Write(self, &pop_op, 1) < 0) @@ -4245,7 +4280,7 @@ save_reduce(PicklerObject *self, PyObject *args, PyObject *obj) } static int -save(PicklerObject *self, PyObject *obj, int pers_save) +save(PickleState *st, PicklerObject *self, PyObject *obj, int pers_save) { PyTypeObject *type; PyObject *reduce_func = NULL; @@ -4263,7 +4298,7 @@ save(PicklerObject *self, PyObject *obj, int pers_save) 0 if it did nothing successfully; 1 if a persistent id was saved. */ - if ((status = save_pers(self, obj)) != 0) + if ((status = save_pers(st, self, obj)) != 0) return status; } @@ -4293,14 +4328,14 @@ save(PicklerObject *self, PyObject *obj, int pers_save) a GET (or BINGET) opcode, instead of pickling the object once again. */ if (PyMemoTable_Get(self->memo, obj)) { - return memo_get(self, obj); + return memo_get(st, self, obj); } if (type == &PyBytes_Type) { - return save_bytes(self, obj); + return save_bytes(st, self, obj); } else if (type == &PyUnicode_Type) { - return save_unicode(self, obj); + return save_unicode(st, self, obj); } /* We're only calling _Py_EnterRecursiveCall here so that atomic @@ -4310,31 +4345,31 @@ save(PicklerObject *self, PyObject *obj, int pers_save) } if (type == &PyDict_Type) { - status = save_dict(self, obj); + status = save_dict(st, self, obj); goto done; } else if (type == &PySet_Type) { - status = save_set(self, obj); + status = save_set(st, self, obj); goto done; } else if (type == &PyFrozenSet_Type) { - status = save_frozenset(self, obj); + status = save_frozenset(st, self, obj); goto done; } else if (type == &PyList_Type) { - status = save_list(self, obj); + status = save_list(st, self, obj); goto done; } else if (type == &PyTuple_Type) { - status = save_tuple(self, obj); + status = save_tuple(st, self, obj); goto done; } else if (type == &PyByteArray_Type) { - status = save_bytearray(self, obj); + status = save_bytearray(st, self, obj); goto done; } else if (type == &PyPickleBuffer_Type) { - status = save_picklebuffer(self, obj); + status = save_picklebuffer(st, self, obj); goto done; } @@ -4354,11 +4389,11 @@ save(PicklerObject *self, PyObject *obj, int pers_save) } if (type == &PyType_Type) { - status = save_type(self, obj); + status = save_type(st, self, obj); goto done; } else if (type == &PyFunction_Type) { - status = save_global(self, obj, NULL); + status = save_global(st, self, obj, NULL); goto done; } @@ -4369,7 +4404,6 @@ save(PicklerObject *self, PyObject *obj, int pers_save) * __reduce_ex__ method, or the object's __reduce__ method. */ if (self->dispatch_table == NULL) { - PickleState *st = _Pickle_GetGlobalState(); reduce_func = PyDict_GetItemWithError(st->dispatch_table, (PyObject *)type); if (reduce_func == NULL) { @@ -4396,7 +4430,7 @@ save(PicklerObject *self, PyObject *obj, int pers_save) reduce_value = _Pickle_FastCall(reduce_func, Py_NewRef(obj)); } else if (PyType_IsSubtype(type, &PyType_Type)) { - status = save_global(self, obj, NULL); + status = save_global(st, self, obj, NULL); goto done; } else { @@ -4428,7 +4462,6 @@ save(PicklerObject *self, PyObject *obj, int pers_save) reduce_value = PyObject_CallNoArgs(reduce_func); } else { - PickleState *st = _Pickle_GetGlobalState(); PyErr_Format(st->PicklingError, "can't pickle '%.200s' object: %R", type->tp_name, obj); @@ -4442,18 +4475,17 @@ save(PicklerObject *self, PyObject *obj, int pers_save) reduce: if (PyUnicode_Check(reduce_value)) { - status = save_global(self, obj, reduce_value); + status = save_global(st, self, obj, reduce_value); goto done; } if (!PyTuple_Check(reduce_value)) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_SetString(st->PicklingError, "__reduce__ must return a string or tuple"); goto error; } - status = save_reduce(self, reduce_value, obj); + status = save_reduce(st, self, reduce_value, obj); if (0) { error: @@ -4469,7 +4501,7 @@ save(PicklerObject *self, PyObject *obj, int pers_save) } static int -dump(PicklerObject *self, PyObject *obj) +dump(PickleState *state, PicklerObject *self, PyObject *obj) { const char stop_op = STOP; int status = -1; @@ -4499,7 +4531,7 @@ dump(PicklerObject *self, PyObject *obj) self->framing = 1; } - if (save(self, obj, 0) < 0 || + if (save(state, self, obj, 0) < 0 || _Pickler_Write(self, &stop_op, 1) < 0 || _Pickler_CommitFrame(self) < 0) goto error; @@ -4546,6 +4578,7 @@ _pickle_Pickler_clear_memo_impl(PicklerObject *self) _pickle.Pickler.dump + cls: defining_class obj: object / @@ -4553,14 +4586,15 @@ Write a pickled representation of the given object to the open file. [clinic start generated code]*/ static PyObject * -_pickle_Pickler_dump(PicklerObject *self, PyObject *obj) -/*[clinic end generated code: output=87ecad1261e02ac7 input=552eb1c0f52260d9]*/ +_pickle_Pickler_dump_impl(PicklerObject *self, PyTypeObject *cls, + PyObject *obj) +/*[clinic end generated code: output=952cf7f68b1445bb input=f949d84151983594]*/ { + PickleState *st = _Pickle_GetStateByClass(cls); /* Check whether the Pickler was initialized correctly (issue3664). Developers often forget to call __init__() in their subclasses, which would trigger a segfault without this check. */ if (self->write == NULL) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_Format(st->PicklingError, "Pickler.__init__() was not called by %s.__init__()", Py_TYPE(self)->tp_name); @@ -4570,7 +4604,7 @@ _pickle_Pickler_dump(PicklerObject *self, PyObject *obj) if (_Pickler_ClearBuffer(self) < 0) return NULL; - if (dump(self, obj) < 0) + if (dump(st, self, obj) < 0) return NULL; if (_Pickler_FlushToFile(self) < 0) @@ -4612,36 +4646,6 @@ static struct PyMethodDef Pickler_methods[] = { {NULL, NULL} /* sentinel */ }; -static void -Pickler_dealloc(PicklerObject *self) -{ - PyObject_GC_UnTrack(self); - - Py_XDECREF(self->output_buffer); - Py_XDECREF(self->write); - Py_XDECREF(self->pers_func); - Py_XDECREF(self->dispatch_table); - Py_XDECREF(self->fast_memo); - Py_XDECREF(self->reducer_override); - Py_XDECREF(self->buffer_callback); - - PyMemoTable_Del(self->memo); - - Py_TYPE(self)->tp_free((PyObject *)self); -} - -static int -Pickler_traverse(PicklerObject *self, visitproc visit, void *arg) -{ - Py_VISIT(self->write); - Py_VISIT(self->pers_func); - Py_VISIT(self->dispatch_table); - Py_VISIT(self->fast_memo); - Py_VISIT(self->reducer_override); - Py_VISIT(self->buffer_callback); - return 0; -} - static int Pickler_clear(PicklerObject *self) { @@ -4661,6 +4665,29 @@ Pickler_clear(PicklerObject *self) return 0; } +static void +Pickler_dealloc(PicklerObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + (void)Pickler_clear(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); +} + +static int +Pickler_traverse(PicklerObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->write); + Py_VISIT(self->pers_func); + Py_VISIT(self->dispatch_table); + Py_VISIT(self->fast_memo); + Py_VISIT(self->reducer_override); + Py_VISIT(self->buffer_callback); + return 0; +} + /*[clinic input] @@ -4870,15 +4897,18 @@ static PyMethodDef picklerproxy_methods[] = { static void PicklerMemoProxy_dealloc(PicklerMemoProxyObject *self) { + PyTypeObject *tp = Py_TYPE(self); PyObject_GC_UnTrack(self); - Py_XDECREF(self->pickler); - PyObject_GC_Del((PyObject *)self); + Py_CLEAR(self->pickler); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); } static int PicklerMemoProxy_traverse(PicklerMemoProxyObject *self, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(self)); Py_VISIT(self->pickler); return 0; } @@ -4890,43 +4920,29 @@ PicklerMemoProxy_clear(PicklerMemoProxyObject *self) return 0; } -static PyTypeObject PicklerMemoProxyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "_pickle.PicklerMemoProxy", /*tp_name*/ - sizeof(PicklerMemoProxyObject), /*tp_basicsize*/ - 0, - (destructor)PicklerMemoProxy_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - PyObject_HashNotImplemented, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - PyObject_GenericSetAttr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - 0, /* tp_doc */ - (traverseproc)PicklerMemoProxy_traverse, /* tp_traverse */ - (inquiry)PicklerMemoProxy_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - picklerproxy_methods, /* tp_methods */ +static PyType_Slot memoproxy_slots[] = { + {Py_tp_dealloc, PicklerMemoProxy_dealloc}, + {Py_tp_traverse, PicklerMemoProxy_traverse}, + {Py_tp_clear, PicklerMemoProxy_clear}, + {Py_tp_methods, picklerproxy_methods}, + {Py_tp_hash, PyObject_HashNotImplemented}, + {0, NULL}, +}; + +static PyType_Spec memoproxy_spec = { + .name = "_pickle.PicklerMemoProxy", + .basicsize = sizeof(PicklerMemoProxyObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = memoproxy_slots, }; static PyObject * PicklerMemoProxy_New(PicklerObject *pickler) { PicklerMemoProxyObject *self; - - self = PyObject_GC_New(PicklerMemoProxyObject, &PicklerMemoProxyType); + PickleState *st = _Pickle_FindStateByType(Py_TYPE(pickler)); + self = PyObject_GC_New(PicklerMemoProxyObject, st->PicklerMemoProxyType); if (self == NULL) return NULL; self->pickler = (PicklerObject*)Py_NewRef(pickler); @@ -4953,7 +4969,8 @@ Pickler_set_memo(PicklerObject *self, PyObject *obj, void *Py_UNUSED(ignored)) return -1; } - if (Py_IS_TYPE(obj, &PicklerMemoProxyType)) { + PickleState *st = _Pickle_FindStateByType(Py_TYPE(self)); + if (Py_IS_TYPE(obj, st->PicklerMemoProxyType)) { PicklerObject *pickler = ((PicklerMemoProxyObject *)obj)->pickler; @@ -5049,47 +5066,27 @@ static PyGetSetDef Pickler_getsets[] = { {NULL} }; -static PyTypeObject Pickler_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_pickle.Pickler" , /*tp_name*/ - sizeof(PicklerObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Pickler_dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_as_async*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - _pickle_Pickler___init____doc__, /*tp_doc*/ - (traverseproc)Pickler_traverse, /*tp_traverse*/ - (inquiry)Pickler_clear, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - Pickler_methods, /*tp_methods*/ - Pickler_members, /*tp_members*/ - Pickler_getsets, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - _pickle_Pickler___init__, /*tp_init*/ - PyType_GenericAlloc, /*tp_alloc*/ - PyType_GenericNew, /*tp_new*/ - PyObject_GC_Del, /*tp_free*/ - 0, /*tp_is_gc*/ +static PyType_Slot pickler_type_slots[] = { + {Py_tp_dealloc, Pickler_dealloc}, + {Py_tp_methods, Pickler_methods}, + {Py_tp_members, Pickler_members}, + {Py_tp_getset, Pickler_getsets}, + {Py_tp_clear, Pickler_clear}, + {Py_tp_doc, (char*)_pickle_Pickler___init____doc__}, + {Py_tp_traverse, Pickler_traverse}, + {Py_tp_init, _pickle_Pickler___init__}, + {Py_tp_new, PyType_GenericNew}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec pickler_type_spec = { + .name = "_pickle.Pickler", + .basicsize = sizeof(PicklerObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = pickler_type_slots, }; /* Temporary helper for calling self.find_class(). @@ -5107,17 +5104,14 @@ find_class(UnpicklerObject *self, PyObject *module_name, PyObject *global_name) } static Py_ssize_t -marker(UnpicklerObject *self) +marker(PickleState *st, UnpicklerObject *self) { - Py_ssize_t mark; - if (self->num_marks < 1) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_SetString(st->UnpicklingError, "could not find MARK"); return -1; } - mark = self->marks[--self->num_marks]; + Py_ssize_t mark = self->marks[--self->num_marks]; self->stack->mark_set = self->num_marks != 0; self->stack->fence = self->num_marks ? self->marks[self->num_marks - 1] : 0; @@ -5125,24 +5119,24 @@ marker(UnpicklerObject *self) } static int -load_none(UnpicklerObject *self) +load_none(PickleState *state, UnpicklerObject *self) { PDATA_APPEND(self->stack, Py_None, -1); return 0; } static int -load_int(UnpicklerObject *self) +load_int(PickleState *state, UnpicklerObject *self) { PyObject *value; char *endptr, *s; Py_ssize_t len; long x; - if ((len = _Unpickler_Readline(self, &s)) < 0) + if ((len = _Unpickler_Readline(state, self, &s)) < 0) return -1; if (len < 2) - return bad_readline(); + return bad_readline(state); errno = 0; /* XXX: Should the base argument of strtol() be explicitly set to 10? @@ -5177,7 +5171,7 @@ load_int(UnpicklerObject *self) } static int -load_bool(UnpicklerObject *self, PyObject *boolean) +load_bool(PickleState *state, UnpicklerObject *self, PyObject *boolean) { assert(boolean == Py_True || boolean == Py_False); PDATA_APPEND(self->stack, boolean, -1); @@ -5257,49 +5251,46 @@ load_binintx(UnpicklerObject *self, char *s, int size) } static int -load_binint(UnpicklerObject *self) +load_binint(PickleState *state, UnpicklerObject *self) { char *s; - - if (_Unpickler_Read(self, &s, 4) < 0) + if (_Unpickler_Read(self, state, &s, 4) < 0) return -1; return load_binintx(self, s, 4); } static int -load_binint1(UnpicklerObject *self) +load_binint1(PickleState *state, UnpicklerObject *self) { char *s; - - if (_Unpickler_Read(self, &s, 1) < 0) + if (_Unpickler_Read(self, state, &s, 1) < 0) return -1; return load_binintx(self, s, 1); } static int -load_binint2(UnpicklerObject *self) +load_binint2(PickleState *state, UnpicklerObject *self) { char *s; - - if (_Unpickler_Read(self, &s, 2) < 0) + if (_Unpickler_Read(self, state, &s, 2) < 0) return -1; return load_binintx(self, s, 2); } static int -load_long(UnpicklerObject *self) +load_long(PickleState *state, UnpicklerObject *self) { PyObject *value; char *s = NULL; Py_ssize_t len; - if ((len = _Unpickler_Readline(self, &s)) < 0) + if ((len = _Unpickler_Readline(state, self, &s)) < 0) return -1; if (len < 2) - return bad_readline(); + return bad_readline(state); /* s[len-2] will usually be 'L' (and s[len-1] is '\n'); we need to remove the 'L' before calling PyLong_FromString. In order to maintain @@ -5320,19 +5311,18 @@ load_long(UnpicklerObject *self) * data following. */ static int -load_counted_long(UnpicklerObject *self, int size) +load_counted_long(PickleState *st, UnpicklerObject *self, int size) { PyObject *value; char *nbytes; char *pdata; assert(size == 1 || size == 4); - if (_Unpickler_Read(self, &nbytes, size) < 0) + if (_Unpickler_Read(self, st, &nbytes, size) < 0) return -1; size = calc_binint(nbytes, size); if (size < 0) { - PickleState *st = _Pickle_GetGlobalState(); /* Corrupt or hostile pickle -- we never write one like this */ PyErr_SetString(st->UnpicklingError, "LONG pickle has negative byte count"); @@ -5343,7 +5333,7 @@ load_counted_long(UnpicklerObject *self, int size) value = PyLong_FromLong(0L); else { /* Read the raw little-endian bytes and convert. */ - if (_Unpickler_Read(self, &pdata, size) < 0) + if (_Unpickler_Read(self, st, &pdata, size) < 0) return -1; value = _PyLong_FromByteArray((unsigned char *)pdata, (size_t)size, 1 /* little endian */ , 1 /* signed */ ); @@ -5355,17 +5345,17 @@ load_counted_long(UnpicklerObject *self, int size) } static int -load_float(UnpicklerObject *self) +load_float(PickleState *state, UnpicklerObject *self) { PyObject *value; char *endptr, *s; Py_ssize_t len; double d; - if ((len = _Unpickler_Readline(self, &s)) < 0) + if ((len = _Unpickler_Readline(state, self, &s)) < 0) return -1; if (len < 2) - return bad_readline(); + return bad_readline(state); errno = 0; d = PyOS_string_to_double(s, &endptr, PyExc_OverflowError); @@ -5384,13 +5374,13 @@ load_float(UnpicklerObject *self) } static int -load_binfloat(UnpicklerObject *self) +load_binfloat(PickleState *state, UnpicklerObject *self) { PyObject *value; double x; char *s; - if (_Unpickler_Read(self, &s, 8) < 0) + if (_Unpickler_Read(self, state, &s, 8) < 0) return -1; x = PyFloat_Unpack8(s, 0); @@ -5405,14 +5395,14 @@ load_binfloat(UnpicklerObject *self) } static int -load_string(UnpicklerObject *self) +load_string(PickleState *st, UnpicklerObject *self) { PyObject *bytes; PyObject *obj; Py_ssize_t len; char *s, *p; - if ((len = _Unpickler_Readline(self, &s)) < 0) + if ((len = _Unpickler_Readline(st, self, &s)) < 0) return -1; /* Strip the newline */ len--; @@ -5422,7 +5412,6 @@ load_string(UnpicklerObject *self) len -= 2; } else { - PickleState *st = _Pickle_GetGlobalState(); PyErr_SetString(st->UnpicklingError, "the STRING opcode argument must be quoted"); return -1; @@ -5453,25 +5442,24 @@ load_string(UnpicklerObject *self) } static int -load_counted_binstring(UnpicklerObject *self, int nbytes) +load_counted_binstring(PickleState *st, UnpicklerObject *self, int nbytes) { PyObject *obj; Py_ssize_t size; char *s; - if (_Unpickler_Read(self, &s, nbytes) < 0) + if (_Unpickler_Read(self, st, &s, nbytes) < 0) return -1; size = calc_binsize(s, nbytes); if (size < 0) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_Format(st->UnpicklingError, "BINSTRING exceeds system's maximum size of %zd bytes", PY_SSIZE_T_MAX); return -1; } - if (_Unpickler_Read(self, &s, size) < 0) + if (_Unpickler_Read(self, st, &s, size) < 0) return -1; /* Convert Python 2.x strings to bytes if the *encoding* given to the @@ -5491,13 +5479,13 @@ load_counted_binstring(UnpicklerObject *self, int nbytes) } static int -load_counted_binbytes(UnpicklerObject *self, int nbytes) +load_counted_binbytes(PickleState *state, UnpicklerObject *self, int nbytes) { PyObject *bytes; Py_ssize_t size; char *s; - if (_Unpickler_Read(self, &s, nbytes) < 0) + if (_Unpickler_Read(self, state, &s, nbytes) < 0) return -1; size = calc_binsize(s, nbytes); @@ -5511,7 +5499,7 @@ load_counted_binbytes(UnpicklerObject *self, int nbytes) bytes = PyBytes_FromStringAndSize(NULL, size); if (bytes == NULL) return -1; - if (_Unpickler_ReadInto(self, PyBytes_AS_STRING(bytes), size) < 0) { + if (_Unpickler_ReadInto(state, self, PyBytes_AS_STRING(bytes), size) < 0) { Py_DECREF(bytes); return -1; } @@ -5521,13 +5509,13 @@ load_counted_binbytes(UnpicklerObject *self, int nbytes) } static int -load_counted_bytearray(UnpicklerObject *self) +load_counted_bytearray(PickleState *state, UnpicklerObject *self) { PyObject *bytearray; Py_ssize_t size; char *s; - if (_Unpickler_Read(self, &s, 8) < 0) { + if (_Unpickler_Read(self, state, &s, 8) < 0) { return -1; } @@ -5543,7 +5531,8 @@ load_counted_bytearray(UnpicklerObject *self) if (bytearray == NULL) { return -1; } - if (_Unpickler_ReadInto(self, PyByteArray_AS_STRING(bytearray), size) < 0) { + char *str = PyByteArray_AS_STRING(bytearray); + if (_Unpickler_ReadInto(state, self, str, size) < 0) { Py_DECREF(bytearray); return -1; } @@ -5553,10 +5542,9 @@ load_counted_bytearray(UnpicklerObject *self) } static int -load_next_buffer(UnpicklerObject *self) +load_next_buffer(PickleState *st, UnpicklerObject *self) { if (self->buffers == NULL) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_SetString(st->UnpicklingError, "pickle stream refers to out-of-band data " "but no *buffers* argument was given"); @@ -5565,7 +5553,6 @@ load_next_buffer(UnpicklerObject *self) PyObject *buf = PyIter_Next(self->buffers); if (buf == NULL) { if (!PyErr_Occurred()) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_SetString(st->UnpicklingError, "not enough out-of-band buffers"); } @@ -5577,11 +5564,11 @@ load_next_buffer(UnpicklerObject *self) } static int -load_readonly_buffer(UnpicklerObject *self) +load_readonly_buffer(PickleState *state, UnpicklerObject *self) { Py_ssize_t len = Py_SIZE(self->stack); if (len <= self->stack->fence) { - return Pdata_stack_underflow(self->stack); + return Pdata_stack_underflow(state, self->stack); } PyObject *obj = self->stack->data[len - 1]; @@ -5603,16 +5590,16 @@ load_readonly_buffer(UnpicklerObject *self) } static int -load_unicode(UnpicklerObject *self) +load_unicode(PickleState *state, UnpicklerObject *self) { PyObject *str; Py_ssize_t len; char *s = NULL; - if ((len = _Unpickler_Readline(self, &s)) < 0) + if ((len = _Unpickler_Readline(state, self, &s)) < 0) return -1; if (len < 1) - return bad_readline(); + return bad_readline(state); str = PyUnicode_DecodeRawUnicodeEscape(s, len - 1, NULL); if (str == NULL) @@ -5623,13 +5610,13 @@ load_unicode(UnpicklerObject *self) } static int -load_counted_binunicode(UnpicklerObject *self, int nbytes) +load_counted_binunicode(PickleState *state, UnpicklerObject *self, int nbytes) { PyObject *str; Py_ssize_t size; char *s; - if (_Unpickler_Read(self, &s, nbytes) < 0) + if (_Unpickler_Read(self, state, &s, nbytes) < 0) return -1; size = calc_binsize(s, nbytes); @@ -5640,7 +5627,7 @@ load_counted_binunicode(UnpicklerObject *self, int nbytes) return -1; } - if (_Unpickler_Read(self, &s, size) < 0) + if (_Unpickler_Read(self, state, &s, size) < 0) return -1; str = PyUnicode_DecodeUTF8(s, size, "surrogatepass"); @@ -5652,14 +5639,14 @@ load_counted_binunicode(UnpicklerObject *self, int nbytes) } static int -load_counted_tuple(UnpicklerObject *self, Py_ssize_t len) +load_counted_tuple(PickleState *state, UnpicklerObject *self, Py_ssize_t len) { PyObject *tuple; if (Py_SIZE(self->stack) < len) - return Pdata_stack_underflow(self->stack); + return Pdata_stack_underflow(state, self->stack); - tuple = Pdata_poptuple(self->stack, Py_SIZE(self->stack) - len); + tuple = Pdata_poptuple(state, self->stack, Py_SIZE(self->stack) - len); if (tuple == NULL) return -1; PDATA_PUSH(self->stack, tuple, -1); @@ -5667,18 +5654,18 @@ load_counted_tuple(UnpicklerObject *self, Py_ssize_t len) } static int -load_tuple(UnpicklerObject *self) +load_tuple(PickleState *state, UnpicklerObject *self) { Py_ssize_t i; - if ((i = marker(self)) < 0) + if ((i = marker(state, self)) < 0) return -1; - return load_counted_tuple(self, Py_SIZE(self->stack) - i); + return load_counted_tuple(state, self, Py_SIZE(self->stack) - i); } static int -load_empty_list(UnpicklerObject *self) +load_empty_list(PickleState *state, UnpicklerObject *self) { PyObject *list; @@ -5689,7 +5676,7 @@ load_empty_list(UnpicklerObject *self) } static int -load_empty_dict(UnpicklerObject *self) +load_empty_dict(PickleState *state, UnpicklerObject *self) { PyObject *dict; @@ -5700,7 +5687,7 @@ load_empty_dict(UnpicklerObject *self) } static int -load_empty_set(UnpicklerObject *self) +load_empty_set(PickleState *state, UnpicklerObject *self) { PyObject *set; @@ -5711,12 +5698,12 @@ load_empty_set(UnpicklerObject *self) } static int -load_list(UnpicklerObject *self) +load_list(PickleState *state, UnpicklerObject *self) { PyObject *list; Py_ssize_t i; - if ((i = marker(self)) < 0) + if ((i = marker(state, self)) < 0) return -1; list = Pdata_poplist(self->stack, i); @@ -5727,12 +5714,12 @@ load_list(UnpicklerObject *self) } static int -load_dict(UnpicklerObject *self) +load_dict(PickleState *st, UnpicklerObject *self) { PyObject *dict, *key, *value; Py_ssize_t i, j, k; - if ((i = marker(self)) < 0) + if ((i = marker(st, self)) < 0) return -1; j = Py_SIZE(self->stack); @@ -5740,7 +5727,6 @@ load_dict(UnpicklerObject *self) return -1; if ((j - i) % 2 != 0) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_SetString(st->UnpicklingError, "odd number of items for DICT"); Py_DECREF(dict); return -1; @@ -5760,16 +5746,16 @@ load_dict(UnpicklerObject *self) } static int -load_frozenset(UnpicklerObject *self) +load_frozenset(PickleState *state, UnpicklerObject *self) { PyObject *items; PyObject *frozenset; Py_ssize_t i; - if ((i = marker(self)) < 0) + if ((i = marker(state, self)) < 0) return -1; - items = Pdata_poptuple(self->stack, i); + items = Pdata_poptuple(state, self->stack, i); if (items == NULL) return -1; @@ -5803,22 +5789,22 @@ instantiate(PyObject *cls, PyObject *args) } static int -load_obj(UnpicklerObject *self) +load_obj(PickleState *state, UnpicklerObject *self) { PyObject *cls, *args, *obj = NULL; Py_ssize_t i; - if ((i = marker(self)) < 0) + if ((i = marker(state, self)) < 0) return -1; if (Py_SIZE(self->stack) - i < 1) - return Pdata_stack_underflow(self->stack); + return Pdata_stack_underflow(state, self->stack); - args = Pdata_poptuple(self->stack, i + 1); + args = Pdata_poptuple(state, self->stack, i + 1); if (args == NULL) return -1; - PDATA_POP(self->stack, cls); + PDATA_POP(state, self->stack, cls); if (cls) { obj = instantiate(cls, args); Py_DECREF(cls); @@ -5832,7 +5818,7 @@ load_obj(UnpicklerObject *self) } static int -load_inst(UnpicklerObject *self) +load_inst(PickleState *state, UnpicklerObject *self) { PyObject *cls = NULL; PyObject *args = NULL; @@ -5843,12 +5829,12 @@ load_inst(UnpicklerObject *self) Py_ssize_t i; char *s; - if ((i = marker(self)) < 0) + if ((i = marker(state, self)) < 0) return -1; - if ((len = _Unpickler_Readline(self, &s)) < 0) + if ((len = _Unpickler_Readline(state, self, &s)) < 0) return -1; if (len < 2) - return bad_readline(); + return bad_readline(state); /* Here it is safe to use PyUnicode_DecodeASCII(), even though non-ASCII identifiers are permitted in Python 3.0, since the INST opcode is only @@ -5857,10 +5843,10 @@ load_inst(UnpicklerObject *self) if (module_name == NULL) return -1; - if ((len = _Unpickler_Readline(self, &s)) >= 0) { + if ((len = _Unpickler_Readline(state, self, &s)) >= 0) { if (len < 2) { Py_DECREF(module_name); - return bad_readline(); + return bad_readline(state); } class_name = PyUnicode_DecodeASCII(s, len - 1, "strict"); if (class_name != NULL) { @@ -5873,7 +5859,7 @@ load_inst(UnpicklerObject *self) if (cls == NULL) return -1; - if ((args = Pdata_poptuple(self->stack, i)) != NULL) { + if ((args = Pdata_poptuple(state, self->stack, i)) != NULL) { obj = instantiate(cls, args); Py_DECREF(args); } @@ -5887,16 +5873,16 @@ load_inst(UnpicklerObject *self) } static void -newobj_unpickling_error(const char * msg, int use_kwargs, PyObject *arg) +newobj_unpickling_error(PickleState *st, const char *msg, int use_kwargs, + PyObject *arg) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_Format(st->UnpicklingError, msg, use_kwargs ? "NEWOBJ_EX" : "NEWOBJ", Py_TYPE(arg)->tp_name); } static int -load_newobj(UnpicklerObject *self, int use_kwargs) +load_newobj(PickleState *state, UnpicklerObject *self, int use_kwargs) { PyObject *cls, *args, *kwargs = NULL; PyObject *obj; @@ -5905,17 +5891,17 @@ load_newobj(UnpicklerObject *self, int use_kwargs) * cls.__new__(cls, *args, **kwargs). */ if (use_kwargs) { - PDATA_POP(self->stack, kwargs); + PDATA_POP(state, self->stack, kwargs); if (kwargs == NULL) { return -1; } } - PDATA_POP(self->stack, args); + PDATA_POP(state, self->stack, args); if (args == NULL) { Py_XDECREF(kwargs); return -1; } - PDATA_POP(self->stack, cls); + PDATA_POP(state, self->stack, cls); if (cls == NULL) { Py_XDECREF(kwargs); Py_DECREF(args); @@ -5923,22 +5909,26 @@ load_newobj(UnpicklerObject *self, int use_kwargs) } if (!PyType_Check(cls)) { - newobj_unpickling_error("%s class argument must be a type, not %.200s", + newobj_unpickling_error(state, + "%s class argument must be a type, not %.200s", use_kwargs, cls); goto error; } if (((PyTypeObject *)cls)->tp_new == NULL) { - newobj_unpickling_error("%s class argument '%.200s' doesn't have __new__", + newobj_unpickling_error(state, + "%s class argument '%.200s' doesn't have __new__", use_kwargs, cls); goto error; } if (!PyTuple_Check(args)) { - newobj_unpickling_error("%s args argument must be a tuple, not %.200s", + newobj_unpickling_error(state, + "%s args argument must be a tuple, not %.200s", use_kwargs, args); goto error; } if (use_kwargs && !PyDict_Check(kwargs)) { - newobj_unpickling_error("%s kwargs argument must be a dict, not %.200s", + newobj_unpickling_error(state, + "%s kwargs argument must be a dict, not %.200s", use_kwargs, kwargs); goto error; } @@ -5961,7 +5951,7 @@ load_newobj(UnpicklerObject *self, int use_kwargs) } static int -load_global(UnpicklerObject *self) +load_global(PickleState *state, UnpicklerObject *self) { PyObject *global = NULL; PyObject *module_name; @@ -5969,18 +5959,18 @@ load_global(UnpicklerObject *self) Py_ssize_t len; char *s; - if ((len = _Unpickler_Readline(self, &s)) < 0) + if ((len = _Unpickler_Readline(state, self, &s)) < 0) return -1; if (len < 2) - return bad_readline(); + return bad_readline(state); module_name = PyUnicode_DecodeUTF8(s, len - 1, "strict"); if (!module_name) return -1; - if ((len = _Unpickler_Readline(self, &s)) >= 0) { + if ((len = _Unpickler_Readline(state, self, &s)) >= 0) { if (len < 2) { Py_DECREF(module_name); - return bad_readline(); + return bad_readline(state); } global_name = PyUnicode_DecodeUTF8(s, len - 1, "strict"); if (global_name) { @@ -5997,17 +5987,16 @@ load_global(UnpicklerObject *self) } static int -load_stack_global(UnpicklerObject *self) +load_stack_global(PickleState *st, UnpicklerObject *self) { PyObject *global; PyObject *module_name; PyObject *global_name; - PDATA_POP(self->stack, global_name); - PDATA_POP(self->stack, module_name); + PDATA_POP(st, self->stack, global_name); + PDATA_POP(st, self->stack, module_name); if (module_name == NULL || !PyUnicode_CheckExact(module_name) || global_name == NULL || !PyUnicode_CheckExact(global_name)) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_SetString(st->UnpicklingError, "STACK_GLOBAL requires str"); Py_XDECREF(global_name); Py_XDECREF(module_name); @@ -6023,22 +6012,22 @@ load_stack_global(UnpicklerObject *self) } static int -load_persid(UnpicklerObject *self) +load_persid(PickleState *st, UnpicklerObject *self) { PyObject *pid, *obj; Py_ssize_t len; char *s; if (self->pers_func) { - if ((len = _Unpickler_Readline(self, &s)) < 0) + if ((len = _Unpickler_Readline(st, self, &s)) < 0) return -1; if (len < 1) - return bad_readline(); + return bad_readline(st); pid = PyUnicode_DecodeASCII(s, len - 1, "strict"); if (pid == NULL) { if (PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) { - PyErr_SetString(_Pickle_GetGlobalState()->UnpicklingError, + PyErr_SetString(st->UnpicklingError, "persistent IDs in protocol 0 must be " "ASCII strings"); } @@ -6054,7 +6043,6 @@ load_persid(UnpicklerObject *self) return 0; } else { - PickleState *st = _Pickle_GetGlobalState(); PyErr_SetString(st->UnpicklingError, "A load persistent id instruction was encountered, " "but no persistent_load function was specified."); @@ -6063,12 +6051,12 @@ load_persid(UnpicklerObject *self) } static int -load_binpersid(UnpicklerObject *self) +load_binpersid(PickleState *st, UnpicklerObject *self) { PyObject *pid, *obj; if (self->pers_func) { - PDATA_POP(self->stack, pid); + PDATA_POP(st, self->stack, pid); if (pid == NULL) return -1; @@ -6081,7 +6069,6 @@ load_binpersid(UnpicklerObject *self) return 0; } else { - PickleState *st = _Pickle_GetGlobalState(); PyErr_SetString(st->UnpicklingError, "A load persistent id instruction was encountered, " "but no persistent_load function was specified."); @@ -6090,7 +6077,7 @@ load_binpersid(UnpicklerObject *self) } static int -load_pop(UnpicklerObject *self) +load_pop(PickleState *state, UnpicklerObject *self) { Py_ssize_t len = Py_SIZE(self->stack); @@ -6107,7 +6094,7 @@ load_pop(UnpicklerObject *self) self->stack->fence = self->num_marks ? self->marks[self->num_marks - 1] : 0; } else if (len <= self->stack->fence) - return Pdata_stack_underflow(self->stack); + return Pdata_stack_underflow(state, self->stack); else { len--; Py_DECREF(self->stack->data[len]); @@ -6117,11 +6104,10 @@ load_pop(UnpicklerObject *self) } static int -load_pop_mark(UnpicklerObject *self) +load_pop_mark(PickleState *state, UnpicklerObject *self) { Py_ssize_t i; - - if ((i = marker(self)) < 0) + if ((i = marker(state, self)) < 0) return -1; Pdata_clear(self->stack, i); @@ -6130,30 +6116,30 @@ load_pop_mark(UnpicklerObject *self) } static int -load_dup(UnpicklerObject *self) +load_dup(PickleState *state, UnpicklerObject *self) { PyObject *last; Py_ssize_t len = Py_SIZE(self->stack); if (len <= self->stack->fence) - return Pdata_stack_underflow(self->stack); + return Pdata_stack_underflow(state, self->stack); last = self->stack->data[len - 1]; PDATA_APPEND(self->stack, last, -1); return 0; } static int -load_get(UnpicklerObject *self) +load_get(PickleState *st, UnpicklerObject *self) { PyObject *key, *value; Py_ssize_t idx; Py_ssize_t len; char *s; - if ((len = _Unpickler_Readline(self, &s)) < 0) + if ((len = _Unpickler_Readline(st, self, &s)) < 0) return -1; if (len < 2) - return bad_readline(); + return bad_readline(st); key = PyLong_FromString(s, NULL, 10); if (key == NULL) @@ -6167,7 +6153,6 @@ load_get(UnpicklerObject *self) value = _Unpickler_MemoGet(self, idx); if (value == NULL) { if (!PyErr_Occurred()) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_Format(st->UnpicklingError, "Memo value not found at index %ld", idx); } Py_DECREF(key); @@ -6180,13 +6165,13 @@ load_get(UnpicklerObject *self) } static int -load_binget(UnpicklerObject *self) +load_binget(PickleState *st, UnpicklerObject *self) { PyObject *value; Py_ssize_t idx; char *s; - if (_Unpickler_Read(self, &s, 1) < 0) + if (_Unpickler_Read(self, st, &s, 1) < 0) return -1; idx = Py_CHARMASK(s[0]); @@ -6195,7 +6180,6 @@ load_binget(UnpicklerObject *self) if (value == NULL) { PyObject *key = PyLong_FromSsize_t(idx); if (key != NULL) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_Format(st->UnpicklingError, "Memo value not found at index %ld", idx); Py_DECREF(key); } @@ -6207,13 +6191,13 @@ load_binget(UnpicklerObject *self) } static int -load_long_binget(UnpicklerObject *self) +load_long_binget(PickleState *st, UnpicklerObject *self) { PyObject *value; Py_ssize_t idx; char *s; - if (_Unpickler_Read(self, &s, 4) < 0) + if (_Unpickler_Read(self, st, &s, 4) < 0) return -1; idx = calc_binsize(s, 4); @@ -6222,7 +6206,6 @@ load_long_binget(UnpicklerObject *self) if (value == NULL) { PyObject *key = PyLong_FromSsize_t(idx); if (key != NULL) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_Format(st->UnpicklingError, "Memo value not found at index %ld", idx); Py_DECREF(key); } @@ -6237,7 +6220,7 @@ load_long_binget(UnpicklerObject *self) * the number of bytes following the opcode, holding the index (code) value. */ static int -load_extension(UnpicklerObject *self, int nbytes) +load_extension(PickleState *st, UnpicklerObject *self, int nbytes) { char *codebytes; /* the nbytes bytes after the opcode */ long code; /* calc_binint returns long */ @@ -6245,10 +6228,9 @@ load_extension(UnpicklerObject *self, int nbytes) PyObject *obj; /* the object to push */ PyObject *pair; /* (module_name, class_name) */ PyObject *module_name, *class_name; - PickleState *st = _Pickle_GetGlobalState(); assert(nbytes == 1 || nbytes == 2 || nbytes == 4); - if (_Unpickler_Read(self, &codebytes, nbytes) < 0) + if (_Unpickler_Read(self, st, &codebytes, nbytes) < 0) return -1; code = calc_binint(codebytes, nbytes); if (code <= 0) { /* note that 0 is forbidden */ @@ -6324,19 +6306,19 @@ load_extension(UnpicklerObject *self, int nbytes) } static int -load_put(UnpicklerObject *self) +load_put(PickleState *state, UnpicklerObject *self) { PyObject *key, *value; Py_ssize_t idx; Py_ssize_t len; char *s = NULL; - if ((len = _Unpickler_Readline(self, &s)) < 0) + if ((len = _Unpickler_Readline(state, self, &s)) < 0) return -1; if (len < 2) - return bad_readline(); + return bad_readline(state); if (Py_SIZE(self->stack) <= self->stack->fence) - return Pdata_stack_underflow(self->stack); + return Pdata_stack_underflow(state, self->stack); value = self->stack->data[Py_SIZE(self->stack) - 1]; key = PyLong_FromString(s, NULL, 10); @@ -6355,17 +6337,17 @@ load_put(UnpicklerObject *self) } static int -load_binput(UnpicklerObject *self) +load_binput(PickleState *state, UnpicklerObject *self) { PyObject *value; Py_ssize_t idx; char *s; - if (_Unpickler_Read(self, &s, 1) < 0) + if (_Unpickler_Read(self, state, &s, 1) < 0) return -1; if (Py_SIZE(self->stack) <= self->stack->fence) - return Pdata_stack_underflow(self->stack); + return Pdata_stack_underflow(state, self->stack); value = self->stack->data[Py_SIZE(self->stack) - 1]; idx = Py_CHARMASK(s[0]); @@ -6374,17 +6356,17 @@ load_binput(UnpicklerObject *self) } static int -load_long_binput(UnpicklerObject *self) +load_long_binput(PickleState *state, UnpicklerObject *self) { PyObject *value; Py_ssize_t idx; char *s; - if (_Unpickler_Read(self, &s, 4) < 0) + if (_Unpickler_Read(self, state, &s, 4) < 0) return -1; if (Py_SIZE(self->stack) <= self->stack->fence) - return Pdata_stack_underflow(self->stack); + return Pdata_stack_underflow(state, self->stack); value = self->stack->data[Py_SIZE(self->stack) - 1]; idx = calc_binsize(s, 4); @@ -6398,19 +6380,19 @@ load_long_binput(UnpicklerObject *self) } static int -load_memoize(UnpicklerObject *self) +load_memoize(PickleState *state, UnpicklerObject *self) { PyObject *value; if (Py_SIZE(self->stack) <= self->stack->fence) - return Pdata_stack_underflow(self->stack); + return Pdata_stack_underflow(state, self->stack); value = self->stack->data[Py_SIZE(self->stack) - 1]; return _Unpickler_MemoPut(self, self->memo_len, value); } static int -do_append(UnpicklerObject *self, Py_ssize_t x) +do_append(PickleState *state, UnpicklerObject *self, Py_ssize_t x) { PyObject *value; PyObject *slice; @@ -6420,7 +6402,7 @@ do_append(UnpicklerObject *self, Py_ssize_t x) len = Py_SIZE(self->stack); if (x > len || x <= self->stack->fence) - return Pdata_stack_underflow(self->stack); + return Pdata_stack_underflow(state, self->stack); if (len == x) /* nothing to do */ return 0; @@ -6485,24 +6467,24 @@ do_append(UnpicklerObject *self, Py_ssize_t x) } static int -load_append(UnpicklerObject *self) +load_append(PickleState *state, UnpicklerObject *self) { if (Py_SIZE(self->stack) - 1 <= self->stack->fence) - return Pdata_stack_underflow(self->stack); - return do_append(self, Py_SIZE(self->stack) - 1); + return Pdata_stack_underflow(state, self->stack); + return do_append(state, self, Py_SIZE(self->stack) - 1); } static int -load_appends(UnpicklerObject *self) +load_appends(PickleState *state, UnpicklerObject *self) { - Py_ssize_t i = marker(self); + Py_ssize_t i = marker(state, self); if (i < 0) return -1; - return do_append(self, i); + return do_append(state, self, i); } static int -do_setitems(UnpicklerObject *self, Py_ssize_t x) +do_setitems(PickleState *st, UnpicklerObject *self, Py_ssize_t x) { PyObject *value, *key; PyObject *dict; @@ -6511,11 +6493,10 @@ do_setitems(UnpicklerObject *self, Py_ssize_t x) len = Py_SIZE(self->stack); if (x > len || x <= self->stack->fence) - return Pdata_stack_underflow(self->stack); + return Pdata_stack_underflow(st, self->stack); if (len == x) /* nothing to do */ return 0; if ((len - x) % 2 != 0) { - PickleState *st = _Pickle_GetGlobalState(); /* Corrupt or hostile pickle -- we never write one like this. */ PyErr_SetString(st->UnpicklingError, "odd number of items for SETITEMS"); @@ -6540,32 +6521,32 @@ do_setitems(UnpicklerObject *self, Py_ssize_t x) } static int -load_setitem(UnpicklerObject *self) +load_setitem(PickleState *state, UnpicklerObject *self) { - return do_setitems(self, Py_SIZE(self->stack) - 2); + return do_setitems(state, self, Py_SIZE(self->stack) - 2); } static int -load_setitems(UnpicklerObject *self) +load_setitems(PickleState *state, UnpicklerObject *self) { - Py_ssize_t i = marker(self); + Py_ssize_t i = marker(state, self); if (i < 0) return -1; - return do_setitems(self, i); + return do_setitems(state, self, i); } static int -load_additems(UnpicklerObject *self) +load_additems(PickleState *state, UnpicklerObject *self) { PyObject *set; Py_ssize_t mark, len, i; - mark = marker(self); + mark = marker(state, self); if (mark < 0) return -1; len = Py_SIZE(self->stack); if (mark > len || mark <= self->stack->fence) - return Pdata_stack_underflow(self->stack); + return Pdata_stack_underflow(state, self->stack); if (len == mark) /* nothing to do */ return 0; @@ -6575,7 +6556,7 @@ load_additems(UnpicklerObject *self) PyObject *items; int status; - items = Pdata_poptuple(self->stack, mark); + items = Pdata_poptuple(state, self->stack, mark); if (items == NULL) return -1; @@ -6609,9 +6590,9 @@ load_additems(UnpicklerObject *self) } static int -load_build(UnpicklerObject *self) +load_build(PickleState *st, UnpicklerObject *self) { - PyObject *state, *inst, *slotstate; + PyObject *inst, *slotstate; PyObject *setstate; int status = 0; @@ -6619,9 +6600,10 @@ load_build(UnpicklerObject *self) * the stack top, possibly mutated via instance.__setstate__(state). */ if (Py_SIZE(self->stack) - 2 < self->stack->fence) - return Pdata_stack_underflow(self->stack); + return Pdata_stack_underflow(st, self->stack); - PDATA_POP(self->stack, state); + PyObject *state; + PDATA_POP(st, self->stack, state); if (state == NULL) return -1; @@ -6665,7 +6647,6 @@ load_build(UnpicklerObject *self) Py_ssize_t i; if (!PyDict_Check(state)) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_SetString(st->UnpicklingError, "state is not a dictionary"); goto error; } @@ -6695,7 +6676,6 @@ load_build(UnpicklerObject *self) Py_ssize_t i; if (!PyDict_Check(slotstate)) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_SetString(st->UnpicklingError, "slot state is not a dictionary"); goto error; @@ -6718,7 +6698,7 @@ load_build(UnpicklerObject *self) } static int -load_mark(UnpicklerObject *self) +load_mark(PickleState *state, UnpicklerObject *self) { /* Note that we split the (pickle.py) stack into two stacks, an @@ -6745,16 +6725,16 @@ load_mark(UnpicklerObject *self) } static int -load_reduce(UnpicklerObject *self) +load_reduce(PickleState *state, UnpicklerObject *self) { PyObject *callable = NULL; PyObject *argtup = NULL; PyObject *obj = NULL; - PDATA_POP(self->stack, argtup); + PDATA_POP(state, self->stack, argtup); if (argtup == NULL) return -1; - PDATA_POP(self->stack, callable); + PDATA_POP(state, self->stack, callable); if (callable) { obj = PyObject_CallObject(callable, argtup); Py_DECREF(callable); @@ -6772,12 +6752,12 @@ load_reduce(UnpicklerObject *self) * is the first opcode for protocols >= 2. */ static int -load_proto(UnpicklerObject *self) +load_proto(PickleState *state, UnpicklerObject *self) { char *s; int i; - if (_Unpickler_Read(self, &s, 1) < 0) + if (_Unpickler_Read(self, state, &s, 1) < 0) return -1; i = (unsigned char)s[0]; @@ -6791,12 +6771,12 @@ load_proto(UnpicklerObject *self) } static int -load_frame(UnpicklerObject *self) +load_frame(PickleState *state, UnpicklerObject *self) { char *s; Py_ssize_t frame_len; - if (_Unpickler_Read(self, &s, 8) < 0) + if (_Unpickler_Read(self, state, &s, 8) < 0) return -1; frame_len = calc_binsize(s, 8); @@ -6807,7 +6787,7 @@ load_frame(UnpicklerObject *self) return -1; } - if (_Unpickler_Read(self, &s, frame_len) < 0) + if (_Unpickler_Read(self, state, &s, frame_len) < 0) return -1; /* Rewind to start of frame */ @@ -6816,7 +6796,7 @@ load_frame(UnpicklerObject *self) } static PyObject * -load(UnpicklerObject *self) +load(PickleState *st, UnpicklerObject *self) { PyObject *value = NULL; char *s = NULL; @@ -6830,14 +6810,13 @@ load(UnpicklerObject *self) /* Convenient macros for the dispatch while-switch loop just below. */ #define OP(opcode, load_func) \ - case opcode: if (load_func(self) < 0) break; continue; + case opcode: if (load_func(st, self) < 0) break; continue; #define OP_ARG(opcode, load_func, arg) \ - case opcode: if (load_func(self, (arg)) < 0) break; continue; + case opcode: if (load_func(st, self, (arg)) < 0) break; continue; while (1) { - if (_Unpickler_Read(self, &s, 1) < 0) { - PickleState *st = _Pickle_GetGlobalState(); + if (_Unpickler_Read(self, st, &s, 1) < 0) { if (PyErr_ExceptionMatches(st->UnpicklingError)) { PyErr_Format(PyExc_EOFError, "Ran out of input"); } @@ -6918,7 +6897,6 @@ load(UnpicklerObject *self) default: { - PickleState *st = _Pickle_GetGlobalState(); unsigned char c = (unsigned char) *s; if (0x20 <= c && c <= 0x7e && c != '\'' && c != '\\') { PyErr_Format(st->UnpicklingError, @@ -6942,7 +6920,7 @@ load(UnpicklerObject *self) if (_Unpickler_SkipConsumed(self) < 0) return NULL; - PDATA_POP(self->stack, value); + PDATA_POP(st, self->stack, value); return value; } @@ -6950,6 +6928,8 @@ load(UnpicklerObject *self) _pickle.Unpickler.load + cls: defining_class + Load a pickle. Read a pickled object representation from the open file object given @@ -6958,24 +6938,25 @@ specified therein. [clinic start generated code]*/ static PyObject * -_pickle_Unpickler_load_impl(UnpicklerObject *self) -/*[clinic end generated code: output=fdcc488aad675b14 input=acbb91a42fa9b7b9]*/ +_pickle_Unpickler_load_impl(UnpicklerObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=cc88168f608e3007 input=f5d2f87e61d5f07f]*/ { UnpicklerObject *unpickler = (UnpicklerObject*)self; + PickleState *st = _Pickle_GetStateByClass(cls); + /* Check whether the Unpickler was initialized correctly. This prevents segfaulting if a subclass overridden __init__ with a function that does not call Unpickler.__init__(). Here, we simply ensure that self->read is not NULL. */ if (unpickler->read == NULL) { - PickleState *st = _Pickle_GetGlobalState(); PyErr_Format(st->UnpicklingError, "Unpickler.__init__() was not called by %s.__init__()", Py_TYPE(unpickler)->tp_name); return NULL; } - return load(unpickler); + return load(st, unpickler); } /* The name of find_class() is misleading. In newer pickle protocols, this @@ -6986,6 +6967,7 @@ _pickle_Unpickler_load_impl(UnpicklerObject *self) _pickle.Unpickler.find_class + cls: defining_class module_name: object global_name: object / @@ -7001,10 +6983,10 @@ needed. Both arguments passed are str objects. [clinic start generated code]*/ static PyObject * -_pickle_Unpickler_find_class_impl(UnpicklerObject *self, +_pickle_Unpickler_find_class_impl(UnpicklerObject *self, PyTypeObject *cls, PyObject *module_name, PyObject *global_name) -/*[clinic end generated code: output=becc08d7f9ed41e3 input=e2e6a865de093ef4]*/ +/*[clinic end generated code: output=99577948abb0be81 input=9577745719219fc7]*/ { PyObject *global; PyObject *module; @@ -7020,7 +7002,7 @@ _pickle_Unpickler_find_class_impl(UnpicklerObject *self, if (self->proto < 3 && self->fix_imports) { PyObject *key; PyObject *item; - PickleState *st = _Pickle_GetGlobalState(); + PickleState *st = _Pickle_GetStateByClass(cls); /* Check if the global (i.e., a function or a class) was renamed or moved to another module. */ @@ -7114,44 +7096,6 @@ static struct PyMethodDef Unpickler_methods[] = { {NULL, NULL} /* sentinel */ }; -static void -Unpickler_dealloc(UnpicklerObject *self) -{ - PyObject_GC_UnTrack((PyObject *)self); - Py_XDECREF(self->readline); - Py_XDECREF(self->readinto); - Py_XDECREF(self->read); - Py_XDECREF(self->peek); - Py_XDECREF(self->stack); - Py_XDECREF(self->pers_func); - Py_XDECREF(self->buffers); - if (self->buffer.buf != NULL) { - PyBuffer_Release(&self->buffer); - self->buffer.buf = NULL; - } - - _Unpickler_MemoCleanup(self); - PyMem_Free(self->marks); - PyMem_Free(self->input_line); - PyMem_Free(self->encoding); - PyMem_Free(self->errors); - - Py_TYPE(self)->tp_free((PyObject *)self); -} - -static int -Unpickler_traverse(UnpicklerObject *self, visitproc visit, void *arg) -{ - Py_VISIT(self->readline); - Py_VISIT(self->readinto); - Py_VISIT(self->read); - Py_VISIT(self->peek); - Py_VISIT(self->stack); - Py_VISIT(self->pers_func); - Py_VISIT(self->buffers); - return 0; -} - static int Unpickler_clear(UnpicklerObject *self) { @@ -7180,6 +7124,30 @@ Unpickler_clear(UnpicklerObject *self) return 0; } +static void +Unpickler_dealloc(UnpicklerObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack((PyObject *)self); + (void)Unpickler_clear(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); +} + +static int +Unpickler_traverse(UnpicklerObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->readline); + Py_VISIT(self->readinto); + Py_VISIT(self->read); + Py_VISIT(self->peek); + Py_VISIT(self->stack); + Py_VISIT(self->pers_func); + Py_VISIT(self->buffers); + return 0; +} + /*[clinic input] _pickle.Unpickler.__init__ @@ -7240,7 +7208,9 @@ _pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file, return -1; } - self->stack = (Pdata *)Pdata_New(); + PyTypeObject *tp = Py_TYPE(self); + PickleState *state = _Pickle_FindStateByType(tp); + self->stack = (Pdata *)Pdata_New(state); if (self->stack == NULL) return -1; @@ -7366,15 +7336,18 @@ static PyMethodDef unpicklerproxy_methods[] = { static void UnpicklerMemoProxy_dealloc(UnpicklerMemoProxyObject *self) { + PyTypeObject *tp = Py_TYPE(self); PyObject_GC_UnTrack(self); - Py_XDECREF(self->unpickler); - PyObject_GC_Del((PyObject *)self); + Py_CLEAR(self->unpickler); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); } static int UnpicklerMemoProxy_traverse(UnpicklerMemoProxyObject *self, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(self)); Py_VISIT(self->unpickler); return 0; } @@ -7386,44 +7359,30 @@ UnpicklerMemoProxy_clear(UnpicklerMemoProxyObject *self) return 0; } -static PyTypeObject UnpicklerMemoProxyType = { - PyVarObject_HEAD_INIT(NULL, 0) - "_pickle.UnpicklerMemoProxy", /*tp_name*/ - sizeof(UnpicklerMemoProxyObject), /*tp_basicsize*/ - 0, - (destructor)UnpicklerMemoProxy_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - PyObject_HashNotImplemented, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - PyObject_GenericSetAttr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - 0, /* tp_doc */ - (traverseproc)UnpicklerMemoProxy_traverse, /* tp_traverse */ - (inquiry)UnpicklerMemoProxy_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - unpicklerproxy_methods, /* tp_methods */ +static PyType_Slot unpickler_memoproxy_slots[] = { + {Py_tp_dealloc, UnpicklerMemoProxy_dealloc}, + {Py_tp_traverse, UnpicklerMemoProxy_traverse}, + {Py_tp_clear, UnpicklerMemoProxy_clear}, + {Py_tp_methods, unpicklerproxy_methods}, + {Py_tp_hash, PyObject_HashNotImplemented}, + {0, NULL}, +}; + +static PyType_Spec unpickler_memoproxy_spec = { + .name = "_pickle.UnpicklerMemoProxy", + .basicsize = sizeof(UnpicklerMemoProxyObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = unpickler_memoproxy_slots, }; static PyObject * UnpicklerMemoProxy_New(UnpicklerObject *unpickler) { + PickleState *state = _Pickle_FindStateByType(Py_TYPE(unpickler)); UnpicklerMemoProxyObject *self; - self = PyObject_GC_New(UnpicklerMemoProxyObject, - &UnpicklerMemoProxyType); + state->UnpicklerMemoProxyType); if (self == NULL) return NULL; self->unpickler = (UnpicklerObject*)Py_NewRef(unpickler); @@ -7452,7 +7411,8 @@ Unpickler_set_memo(UnpicklerObject *self, PyObject *obj, void *Py_UNUSED(ignored return -1; } - if (Py_IS_TYPE(obj, &UnpicklerMemoProxyType)) { + PickleState *state = _Pickle_FindStateByType(Py_TYPE(self)); + if (Py_IS_TYPE(obj, state->UnpicklerMemoProxyType)) { UnpicklerObject *unpickler = ((UnpicklerMemoProxyObject *)obj)->unpickler; @@ -7554,47 +7514,26 @@ static PyGetSetDef Unpickler_getsets[] = { {NULL} }; -static PyTypeObject Unpickler_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_pickle.Unpickler", /*tp_name*/ - sizeof(UnpicklerObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Unpickler_dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_as_async*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - _pickle_Unpickler___init____doc__, /*tp_doc*/ - (traverseproc)Unpickler_traverse, /*tp_traverse*/ - (inquiry)Unpickler_clear, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - Unpickler_methods, /*tp_methods*/ - 0, /*tp_members*/ - Unpickler_getsets, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - _pickle_Unpickler___init__, /*tp_init*/ - PyType_GenericAlloc, /*tp_alloc*/ - PyType_GenericNew, /*tp_new*/ - PyObject_GC_Del, /*tp_free*/ - 0, /*tp_is_gc*/ +static PyType_Slot unpickler_type_slots[] = { + {Py_tp_dealloc, Unpickler_dealloc}, + {Py_tp_doc, (char *)_pickle_Unpickler___init____doc__}, + {Py_tp_traverse, Unpickler_traverse}, + {Py_tp_clear, Unpickler_clear}, + {Py_tp_methods, Unpickler_methods}, + {Py_tp_getset, Unpickler_getsets}, + {Py_tp_init, _pickle_Unpickler___init__}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_new, PyType_GenericNew}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec unpickler_type_spec = { + .name = "_pickle.Unpickler", + .basicsize = sizeof(UnpicklerObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = unpickler_type_slots, }; /*[clinic input] @@ -7643,7 +7582,8 @@ _pickle_dump_impl(PyObject *module, PyObject *obj, PyObject *file, PyObject *buffer_callback) /*[clinic end generated code: output=706186dba996490c input=5ed6653da99cd97c]*/ { - PicklerObject *pickler = _Pickler_New(); + PickleState *state = _Pickle_GetState(module); + PicklerObject *pickler = _Pickler_New(state); if (pickler == NULL) return NULL; @@ -7657,7 +7597,7 @@ _pickle_dump_impl(PyObject *module, PyObject *obj, PyObject *file, if (_Pickler_SetBufferCallback(pickler, buffer_callback) < 0) goto error; - if (dump(pickler, obj) < 0) + if (dump(state, pickler, obj) < 0) goto error; if (_Pickler_FlushToFile(pickler) < 0) @@ -7708,7 +7648,8 @@ _pickle_dumps_impl(PyObject *module, PyObject *obj, PyObject *protocol, /*[clinic end generated code: output=fbab0093a5580fdf input=e543272436c6f987]*/ { PyObject *result; - PicklerObject *pickler = _Pickler_New(); + PickleState *state = _Pickle_GetState(module); + PicklerObject *pickler = _Pickler_New(state); if (pickler == NULL) return NULL; @@ -7719,7 +7660,7 @@ _pickle_dumps_impl(PyObject *module, PyObject *obj, PyObject *protocol, if (_Pickler_SetBufferCallback(pickler, buffer_callback) < 0) goto error; - if (dump(pickler, obj) < 0) + if (dump(state, pickler, obj) < 0) goto error; result = _Pickler_GetString(pickler); @@ -7774,7 +7715,7 @@ _pickle_load_impl(PyObject *module, PyObject *file, int fix_imports, /*[clinic end generated code: output=250452d141c23e76 input=46c7c31c92f4f371]*/ { PyObject *result; - UnpicklerObject *unpickler = _Unpickler_New(); + UnpicklerObject *unpickler = _Unpickler_New(module); if (unpickler == NULL) return NULL; @@ -7790,7 +7731,8 @@ _pickle_load_impl(PyObject *module, PyObject *file, int fix_imports, unpickler->fix_imports = fix_imports; - result = load(unpickler); + PickleState *state = _Pickle_GetState(module); + result = load(state, unpickler); Py_DECREF(unpickler); return result; @@ -7834,7 +7776,7 @@ _pickle_loads_impl(PyObject *module, PyObject *data, int fix_imports, /*[clinic end generated code: output=82ac1e6b588e6d02 input=b3615540d0535087]*/ { PyObject *result; - UnpicklerObject *unpickler = _Unpickler_New(); + UnpicklerObject *unpickler = _Unpickler_New(module); if (unpickler == NULL) return NULL; @@ -7850,7 +7792,8 @@ _pickle_loads_impl(PyObject *module, PyObject *data, int fix_imports, unpickler->fix_imports = fix_imports; - result = load(unpickler); + PickleState *state = _Pickle_GetState(module); + result = load(state, unpickler); Py_DECREF(unpickler); return result; @@ -7898,81 +7841,94 @@ pickle_traverse(PyObject *m, visitproc visit, void *arg) Py_VISIT(st->codecs_encode); Py_VISIT(st->getattr); Py_VISIT(st->partial); + Py_VISIT(st->Pickler_Type); + Py_VISIT(st->Unpickler_Type); + Py_VISIT(st->Pdata_Type); + Py_VISIT(st->PicklerMemoProxyType); + Py_VISIT(st->UnpicklerMemoProxyType); return 0; } -static struct PyModuleDef _picklemodule = { - PyModuleDef_HEAD_INIT, - "_pickle", /* m_name */ - pickle_module_doc, /* m_doc */ - sizeof(PickleState), /* m_size */ - pickle_methods, /* m_methods */ - NULL, /* m_reload */ - pickle_traverse, /* m_traverse */ - pickle_clear, /* m_clear */ - (freefunc)pickle_free /* m_free */ -}; - -PyMODINIT_FUNC -PyInit__pickle(void) +static int +_pickle_exec(PyObject *m) { - PyObject *m; - PickleState *st; + PickleState *st = _Pickle_GetState(m); - m = PyState_FindModule(&_picklemodule); - if (m) { - return Py_NewRef(m); - } +#define CREATE_TYPE(mod, type, spec) \ + do { \ + type = (PyTypeObject *)PyType_FromMetaclass(NULL, mod, spec, NULL); \ + if (type == NULL) { \ + return -1; \ + } \ + } while (0) - if (PyType_Ready(&Pdata_Type) < 0) - return NULL; - if (PyType_Ready(&PicklerMemoProxyType) < 0) - return NULL; - if (PyType_Ready(&UnpicklerMemoProxyType) < 0) - return NULL; + CREATE_TYPE(m, st->Pdata_Type, &pdata_spec); + CREATE_TYPE(m, st->PicklerMemoProxyType, &memoproxy_spec); + CREATE_TYPE(m, st->UnpicklerMemoProxyType, &unpickler_memoproxy_spec); + CREATE_TYPE(m, st->Pickler_Type, &pickler_type_spec); + CREATE_TYPE(m, st->Unpickler_Type, &unpickler_type_spec); - /* Create the module and add the functions. */ - m = PyModule_Create(&_picklemodule); - if (m == NULL) - return NULL; +#undef CREATE_TYPE /* Add types */ - if (PyModule_AddType(m, &Pickler_Type) < 0) { - return NULL; + if (PyModule_AddType(m, &PyPickleBuffer_Type) < 0) { + return -1; } - if (PyModule_AddType(m, &Unpickler_Type) < 0) { - return NULL; + if (PyModule_AddType(m, st->Pickler_Type) < 0) { + return -1; } - if (PyModule_AddType(m, &PyPickleBuffer_Type) < 0) { - return NULL; + if (PyModule_AddType(m, st->Unpickler_Type) < 0) { + return -1; } - st = _Pickle_GetState(m); - /* Initialize the exceptions. */ st->PickleError = PyErr_NewException("_pickle.PickleError", NULL, NULL); if (st->PickleError == NULL) - return NULL; + return -1; st->PicklingError = \ PyErr_NewException("_pickle.PicklingError", st->PickleError, NULL); if (st->PicklingError == NULL) - return NULL; + return -1; st->UnpicklingError = \ PyErr_NewException("_pickle.UnpicklingError", st->PickleError, NULL); if (st->UnpicklingError == NULL) - return NULL; + return -1; if (PyModule_AddObjectRef(m, "PickleError", st->PickleError) < 0) { - return NULL; + return -1; } if (PyModule_AddObjectRef(m, "PicklingError", st->PicklingError) < 0) { - return NULL; + return -1; } if (PyModule_AddObjectRef(m, "UnpicklingError", st->UnpicklingError) < 0) { - return NULL; + return -1; } + if (_Pickle_InitState(st) < 0) - return NULL; + return -1; - return m; + return 0; +} + +static PyModuleDef_Slot pickle_slots[] = { + {Py_mod_exec, _pickle_exec}, + {0, NULL}, +}; + +static struct PyModuleDef _picklemodule = { + PyModuleDef_HEAD_INIT, + .m_name = "_pickle", + .m_doc = pickle_module_doc, + .m_size = sizeof(PickleState), + .m_methods = pickle_methods, + .m_slots = pickle_slots, + .m_traverse = pickle_traverse, + .m_clear = pickle_clear, + .m_free = (freefunc)pickle_free, +}; + +PyMODINIT_FUNC +PyInit__pickle(void) +{ + return PyModuleDef_Init(&_picklemodule); } diff --git a/Modules/clinic/_pickle.c.h b/Modules/clinic/_pickle.c.h index adb3abc5eb23..539acc34a05c 100644 --- a/Modules/clinic/_pickle.c.h +++ b/Modules/clinic/_pickle.c.h @@ -38,7 +38,42 @@ PyDoc_STRVAR(_pickle_Pickler_dump__doc__, "Write a pickled representation of the given object to the open file."); #define _PICKLE_PICKLER_DUMP_METHODDEF \ - {"dump", (PyCFunction)_pickle_Pickler_dump, METH_O, _pickle_Pickler_dump__doc__}, + {"dump", _PyCFunction_CAST(_pickle_Pickler_dump), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _pickle_Pickler_dump__doc__}, + +static PyObject * +_pickle_Pickler_dump_impl(PicklerObject *self, PyTypeObject *cls, + PyObject *obj); + +static PyObject * +_pickle_Pickler_dump(PicklerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "dump", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *obj; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + obj = args[0]; + return_value = _pickle_Pickler_dump_impl(self, cls, obj); + +exit: + return return_value; +} PyDoc_STRVAR(_pickle_Pickler___sizeof____doc__, "__sizeof__($self, /)\n" @@ -242,15 +277,19 @@ PyDoc_STRVAR(_pickle_Unpickler_load__doc__, "specified therein."); #define _PICKLE_UNPICKLER_LOAD_METHODDEF \ - {"load", (PyCFunction)_pickle_Unpickler_load, METH_NOARGS, _pickle_Unpickler_load__doc__}, + {"load", _PyCFunction_CAST(_pickle_Unpickler_load), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _pickle_Unpickler_load__doc__}, static PyObject * -_pickle_Unpickler_load_impl(UnpicklerObject *self); +_pickle_Unpickler_load_impl(UnpicklerObject *self, PyTypeObject *cls); static PyObject * -_pickle_Unpickler_load(UnpicklerObject *self, PyObject *Py_UNUSED(ignored)) +_pickle_Unpickler_load(UnpicklerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _pickle_Unpickler_load_impl(self); + if (nargs) { + PyErr_SetString(PyExc_TypeError, "load() takes no arguments"); + return NULL; + } + return _pickle_Unpickler_load_impl(self, cls); } PyDoc_STRVAR(_pickle_Unpickler_find_class__doc__, @@ -267,26 +306,41 @@ PyDoc_STRVAR(_pickle_Unpickler_find_class__doc__, "needed. Both arguments passed are str objects."); #define _PICKLE_UNPICKLER_FIND_CLASS_METHODDEF \ - {"find_class", _PyCFunction_CAST(_pickle_Unpickler_find_class), METH_FASTCALL, _pickle_Unpickler_find_class__doc__}, + {"find_class", _PyCFunction_CAST(_pickle_Unpickler_find_class), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _pickle_Unpickler_find_class__doc__}, static PyObject * -_pickle_Unpickler_find_class_impl(UnpicklerObject *self, +_pickle_Unpickler_find_class_impl(UnpicklerObject *self, PyTypeObject *cls, PyObject *module_name, PyObject *global_name); static PyObject * -_pickle_Unpickler_find_class(UnpicklerObject *self, PyObject *const *args, Py_ssize_t nargs) +_pickle_Unpickler_find_class(UnpicklerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "find_class", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; PyObject *module_name; PyObject *global_name; - if (!_PyArg_CheckPositional("find_class", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf); + if (!args) { goto exit; } module_name = args[0]; global_name = args[1]; - return_value = _pickle_Unpickler_find_class_impl(self, module_name, global_name); + return_value = _pickle_Unpickler_find_class_impl(self, cls, module_name, global_name); exit: return return_value; @@ -980,4 +1034,4 @@ _pickle_loads(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObjec exit: return return_value; } -/*[clinic end generated code: output=730dc26938561313 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a0e04b85e7bae626 input=a9049054013a1b77]*/ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index e0e45265209f..0620c7e13925 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -390,11 +390,6 @@ Modules/_decimal/_decimal.c - PyDecContextManager_Type - Modules/_decimal/_decimal.c - PyDecContext_Type - Modules/_decimal/_decimal.c - PyDecSignalDictMixin_Type - Modules/_decimal/_decimal.c - PyDec_Type - -Modules/_pickle.c - Pdata_Type - -Modules/_pickle.c - PicklerMemoProxyType - -Modules/_pickle.c - Pickler_Type - -Modules/_pickle.c - UnpicklerMemoProxyType - -Modules/_pickle.c - Unpickler_Type - Modules/ossaudiodev.c - OSSAudioType - Modules/ossaudiodev.c - OSSMixerType - Modules/socketmodule.c - sock_type - From webhook-mailer at python.org Tue Apr 4 10:51:47 2023 From: webhook-mailer at python.org (Yhg1s) Date: Tue, 04 Apr 2023 14:51:47 -0000 Subject: [Python-checkins] Fix a compiler warning in _xxsubinterpretermodule.c (#103245) Message-ID: https://github.com/python/cpython/commit/89e6a3446184925ee7f17cd0d948c7784a88b8d7 commit: 89e6a3446184925ee7f17cd0d948c7784a88b8d7 branch: main author: T. Wouters committer: Yhg1s date: 2023-04-04T16:51:30+02:00 summary: Fix a compiler warning in _xxsubinterpretermodule.c (#103245) Fix a (correct) warning about potential uses of uninitialized memory in _xxsubinterpreter. Unlike newly allocated PyObject structs or global structs, stack-allocated structs are not initialised, and a few places in the code expect the _sharedexception struct data to be either NULL or initialised. files: M Modules/_xxsubinterpretersmodule.c diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 9648f080cd75..11164676c4d1 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -481,7 +481,7 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp, } // Run the script. - _sharedexception exc; + _sharedexception exc = {NULL, NULL}; int result = _run_script(interp, codestr, shared, &exc); // Switch back. From webhook-mailer at python.org Tue Apr 4 12:00:26 2023 From: webhook-mailer at python.org (zooba) Date: Tue, 04 Apr 2023 16:00:26 -0000 Subject: [Python-checkins] bpo-44844: Enable detection of Microsoft Edge browser in webbrowser module (GH-29908) Message-ID: https://github.com/python/cpython/commit/fd1947ecfba589feebd48c1ebb60d1c01ee0a89d commit: fd1947ecfba589feebd48c1ebb60d1c01ee0a89d branch: main author: Steve Dower committer: zooba date: 2023-04-04T17:00:03+01:00 summary: bpo-44844: Enable detection of Microsoft Edge browser in webbrowser module (GH-29908) files: A Misc/NEWS.d/next/Library/2021-12-03-23-00-56.bpo-44844.tvg2VY.rst M Lib/test/test_webbrowser.py M Lib/webbrowser.py diff --git a/Lib/test/test_webbrowser.py b/Lib/test/test_webbrowser.py index 147a113c7fd7..2d695bc88313 100644 --- a/Lib/test/test_webbrowser.py +++ b/Lib/test/test_webbrowser.py @@ -95,6 +95,31 @@ def test_open_new_tab(self): arguments=[URL]) +class EdgeCommandTest(CommandTestMixin, unittest.TestCase): + + browser_class = webbrowser.Edge + + def test_open(self): + self._test('open', + options=[], + arguments=[URL]) + + def test_open_with_autoraise_false(self): + self._test('open', kw=dict(autoraise=False), + options=[], + arguments=[URL]) + + def test_open_new(self): + self._test('open_new', + options=['--new-window'], + arguments=[URL]) + + def test_open_new_tab(self): + self._test('open_new_tab', + options=[], + arguments=[URL]) + + class MozillaCommandTest(CommandTestMixin, unittest.TestCase): browser_class = webbrowser.Mozilla diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index d98c5997d2f4..b86d131f030d 100755 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -400,6 +400,16 @@ def open(self, url, new=0, autoraise=True): return ok +class Edge(UnixBrowser): + "Launcher class for Microsoft Edge browser." + + remote_args = ['%action', '%s'] + remote_action = "" + remote_action_newwin = "--new-window" + remote_action_newtab = "" + background = True + + # # Platform support for Unix # @@ -456,6 +466,10 @@ def register_X_browsers(): register("opera", None, Opera("opera")) + if shutil.which("microsoft-edge"): + register("microsoft-edge", None, Edge("microsoft-edge")) + + def register_standard_browsers(): global _tryorder _tryorder = [] @@ -487,6 +501,8 @@ def register_standard_browsers(): "opera", edge64, edge32): if shutil.which(browser): register(browser, None, BackgroundBrowser(browser)) + if shutil.which("MicrosoftEdge.exe"): + register("microsoft-edge", None, Edge("MicrosoftEdge.exe")) else: # Prefer X browsers if present if os.environ.get("DISPLAY") or os.environ.get("WAYLAND_DISPLAY"): diff --git a/Misc/NEWS.d/next/Library/2021-12-03-23-00-56.bpo-44844.tvg2VY.rst b/Misc/NEWS.d/next/Library/2021-12-03-23-00-56.bpo-44844.tvg2VY.rst new file mode 100644 index 000000000000..f0c91236dfdf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-12-03-23-00-56.bpo-44844.tvg2VY.rst @@ -0,0 +1 @@ +Enables :mod:`webbrowser` to detect and launch Microsoft Edge browser. From webhook-mailer at python.org Tue Apr 4 14:42:19 2023 From: webhook-mailer at python.org (ned-deily) Date: Tue, 04 Apr 2023 18:42:19 -0000 Subject: [Python-checkins] =?utf-8?q?=5B3=2E10=5D_gh-103207=3A_Add_instru?= =?utf-8?q?ctions_to_the_macOS_installer_welcome_display_on_how_to_workaro?= =?utf-8?q?und_the_macOS_13_Ventura_=E2=80=9CThe_installer_encountered_an_?= =?utf-8?b?ZXJyb3LigJ0gZmFpbHVyZS4gKEdILTEwMzI1Myk=?= Message-ID: https://github.com/python/cpython/commit/ec80ffe39acc41ab43bec33d6fa9900e8eff37e3 commit: ec80ffe39acc41ab43bec33d6fa9900e8eff37e3 branch: 3.10 author: Ned Deily committer: ned-deily date: 2023-04-04T14:42:10-04:00 summary: [3.10] gh-103207: Add instructions to the macOS installer welcome display on how to workaround the macOS 13 Ventura ?The installer encountered an error? failure. (GH-103253) files: A Misc/NEWS.d/next/macOS/2023-04-04-13-37-28.gh-issue-103207.x0vvQp.rst M Mac/BuildScript/resources/Welcome.rtf diff --git a/Mac/BuildScript/resources/Welcome.rtf b/Mac/BuildScript/resources/Welcome.rtf index 57ffdb53d6f2..1be87b64e1fd 100644 --- a/Mac/BuildScript/resources/Welcome.rtf +++ b/Mac/BuildScript/resources/Welcome.rtf @@ -1,9 +1,9 @@ -{\rtf1\ansi\ansicpg1252\cocoartf2580 +{\rtf1\ansi\ansicpg1252\cocoartf2708 \cocoascreenfonts1\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;\f2\fmodern\fcharset0 CourierNewPSMT; -} -{\colortbl;\red255\green255\blue255;} -{\*\expandedcolortbl;;} -\paperw11900\paperh16840\margl1440\margr1440\vieww12200\viewh10880\viewkind0 +\f3\fnil\fcharset0 HelveticaNeue;\f4\fnil\fcharset0 HelveticaNeue-Bold;} +{\colortbl;\red255\green255\blue255;\red24\green26\blue30;\red255\green255\blue255;} +{\*\expandedcolortbl;;\cssrgb\c12157\c13725\c15686;\cssrgb\c100000\c100000\c100000;} +\margl1440\margr1440\vieww12200\viewh10880\viewkind0 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\partightenfactor0 \f0\fs24 \cf0 This package will install @@ -12,8 +12,9 @@ \f1\b macOS $MACOSX_DEPLOYMENT_TARGET \f0\b0 .\ \ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\partightenfactor0 -\f1\b Python for macOS +\f1\b \cf0 Python for macOS \f0\b0 consists of the {\field{\*\fldinst{HYPERLINK "https://www.python.org"}}{\fldrslt Python}} programming language interpreter and its batteries-included standard library to allow easy access to macOS features. It also includes the Python integrated development environment, \f1\b IDLE \f0\b0 . You can also use the included @@ -23,4 +24,34 @@ At the end of this install, click on \f2 Install Certificates \f0 to install a set of current SSL root certificates.\ +\ + +\f1\b macOS 13 Ventura users +\f0\b0 : due to an issue with macOS +\f1\b Installer +\f0\b0 app, installation of some +\f3 \cf2 \cb3 \expnd0\expndtw0\kerning0 +third-party +\f0 \cf0 \cb1 \kerning1\expnd0\expndtw0 packages including this Python package may fail with a vague +\f4\b \cf2 \cb3 \expnd0\expndtw0\kerning0 +\'93The installer encountered an error\'94 +\f3\b0 \cf2 message if the +\f4\b \cf2 Installer +\f3\b0 \cf2 app does not have permission to access the folder containing the downloaded installer file, typically in the +\f4\b \cf2 Downloads +\f3\b0 \cf2 folder. Go to +\f4\b \cf2 System Settings +\f3\b0 \cf2 -> +\f4\b \cf2 Privacy & Security +\f3\b0 \cf2 -> +\f4\b \cf2 Files and Folders +\f3\b0 \cf2 , then click the mark in front of +\f4\b \cf2 Installer +\f3\b0 \cf2 to expand, and enable +\f4\b \cf2 Downloads Folder +\f0\b0 \cf0 \cb1 \kerning1\expnd0\expndtw0 by moving the toggle to the right +\f3 \cf2 \cb3 \expnd0\expndtw0\kerning0 +. See {\field{\*\fldinst{HYPERLINK "https://github.com/python/cpython/issues/103207"}}{\fldrslt https://github.com/python/cpython/issues/103207}} for up-to-date information on this issue. +\f0 \cf0 \cb1 \kerning1\expnd0\expndtw0 \ +\ } \ No newline at end of file diff --git a/Misc/NEWS.d/next/macOS/2023-04-04-13-37-28.gh-issue-103207.x0vvQp.rst b/Misc/NEWS.d/next/macOS/2023-04-04-13-37-28.gh-issue-103207.x0vvQp.rst new file mode 100644 index 000000000000..3c176e3a6b53 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-04-04-13-37-28.gh-issue-103207.x0vvQp.rst @@ -0,0 +1,2 @@ +Add instructions to the macOS installer welcome display on how to workaround +the macOS 13 Ventura ?The installer encountered an error? failure. From webhook-mailer at python.org Tue Apr 4 16:03:47 2023 From: webhook-mailer at python.org (Yhg1s) Date: Tue, 04 Apr 2023 20:03:47 -0000 Subject: [Python-checkins] Python 3.12.0a7 Message-ID: https://github.com/python/cpython/commit/b861ba4a8247af8159df1e01d33157cf57705067 commit: b861ba4a8247af8159df1e01d33157cf57705067 branch: main author: Thomas Wouters committer: Yhg1s date: 2023-04-04T17:52:42+02:00 summary: Python 3.12.0a7 files: A Misc/NEWS.d/3.12.0a7.rst D Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst D Misc/NEWS.d/next/Build/2023-03-23-20-58-56.gh-issue-102973.EaJUrw.rst D Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst D Misc/NEWS.d/next/Core and Builtins/2020-07-04-09-04-41.bpo-1635741.ZsP31Y.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-21-17-22-06.gh-issue-101865.fwrTOA.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-26-11-43-56.gh-issue-102255.cRnI5x.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-26-13-12-55.gh-issue-102213.fTH8X7.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-27-15-48-31.gh-issue-102300.8o-_Mt.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-03-23-21-16.gh-issue-102406.XLqYO3.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-08-08-37-36.gh-issue-102491.SFvvsC.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-09-13-57-35.gh-issue-90997.J-Yhn2.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-14-00-11-46.gh-issue-102594.BjU-m2.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-16-14-44-29.gh-issue-102755.j1GxlV.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-21-00-46-36.gh-issue-102859.PRkGca.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-24-02-50-33.gh-issue-89987.oraTzh.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-31-12-22-25.gh-issue-102192.gYxJP_.rst D Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst D Misc/NEWS.d/next/Library/2019-03-15-22-50-27.bpo-36305.Pbkv6u.rst D Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-72346.pC7gnM.rst D Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst D Misc/NEWS.d/next/Library/2022-07-09-13-07-30.gh-issue-94684.nV5yno.rst D Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst D Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst D Misc/NEWS.d/next/Library/2022-10-10-19-14-51.gh-issue-98169.DBWIxL.rst D Misc/NEWS.d/next/Library/2022-11-24-13-23-07.gh-issue-48330.6uAX9F.rst D Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst D Misc/NEWS.d/next/Library/2022-12-16-10-27-58.gh-issue-89727.y64ZLM.rst D Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst D Misc/NEWS.d/next/Library/2023-01-27-14-51-07.gh-issue-101313.10AEXh.rst D Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst D Misc/NEWS.d/next/Library/2023-02-18-23-03-50.gh-issue-98886.LkKGWv.rst D Misc/NEWS.d/next/Library/2023-02-19-01-49-46.gh-issue-102038.n3if3D.rst D Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst D Misc/NEWS.d/next/Library/2023-02-21-11-56-16.gh-issue-102103.Dj0WEj.rst D Misc/NEWS.d/next/Library/2023-02-26-17-29-57.gh-issue-79940.SAfmAy.rst D Misc/NEWS.d/next/Library/2023-03-03-19-53-08.gh-issue-102378.kRdOZc.rst D Misc/NEWS.d/next/Library/2023-03-04-20-58-29.gh-issue-74468.Ac5Ew_.rst D Misc/NEWS.d/next/Library/2023-03-08-23-08-38.gh-issue-102519.wlcsFI.rst D Misc/NEWS.d/next/Library/2023-03-10-13-21-16.gh-issue-102578.-gujoI.rst D Misc/NEWS.d/next/Library/2023-03-10-13-51-21.gh-issue-100112.VHh4mw.rst D Misc/NEWS.d/next/Library/2023-03-13-12-05-55.gh-issue-102615.NcA_ZL.rst D Misc/NEWS.d/next/Library/2023-03-13-18-27-00.gh-issue-102670.GyoThv.rst D Misc/NEWS.d/next/Library/2023-03-16-08-17-29.gh-issue-102748.WNACpI.rst D Misc/NEWS.d/next/Library/2023-03-16-16-43-04.gh-issue-78530.Lr8eq_.rst D Misc/NEWS.d/next/Library/2023-03-17-19-14-26.gh-issue-76846.KEamjK.rst D Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst D Misc/NEWS.d/next/Library/2023-03-19-15-30-59.gh-issue-102828.NKClXg.rst D Misc/NEWS.d/next/Library/2023-03-20-12-21-19.gh-issue-102839.RjRi12.rst D Misc/NEWS.d/next/Library/2023-03-21-15-17-07.gh-issue-102871.U9mchn.rst D Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst D Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst D Misc/NEWS.d/next/Library/2023-03-25-02-08-05.gh-issue-103023.Qfn7Hl.rst D Misc/NEWS.d/next/Library/2023-03-25-16-57-18.gh-issue-102433.L-7x2Q.rst D Misc/NEWS.d/next/Library/2023-03-26-20-54-57.gh-issue-103046.xBlA2l.rst D Misc/NEWS.d/next/Library/2023-03-27-15-01-16.gh-issue-103056.-Efh5Q.rst D Misc/NEWS.d/next/Library/2023-03-27-19-21-51.gh-issue-102549.NQ6Nlv.rst D Misc/NEWS.d/next/Library/2023-03-28-05-14-59.gh-issue-103068.YQTmrA.rst D Misc/NEWS.d/next/Library/2023-03-28-15-12-53.gh-issue-103085.DqNehf.rst D Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst D Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst D Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst D Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-102809.2F1Byz.rst D Misc/NEWS.d/next/Windows/2023-02-22-17-26-10.gh-issue-99726.76t957.rst D Misc/NEWS.d/next/Windows/2023-03-14-10-52-43.gh-issue-102690.sbXtqk.rst M Include/patchlevel.h M Lib/pydoc_data/topics.py M README.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 049cdfa30897..1a8a6d9c8f7a 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 12 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA -#define PY_RELEASE_SERIAL 6 +#define PY_RELEASE_SERIAL 7 /* Version as a string */ -#define PY_VERSION "3.12.0a6+" +#define PY_VERSION "3.12.0a7" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index ad1b6aca6b95..1babb5ce9476 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Tue Mar 7 22:42:28 2023 +# Autogenerated by Sphinx on Tue Apr 4 17:52:21 2023 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' @@ -1134,10 +1134,11 @@ 'future, a\n' ' check may be added to prevent this.\n' '\n' - '* Nonempty *__slots__* does not work for classes derived ' - 'from\n' - ' ?variable-length? built-in types such as "int", ' - '"bytes" and "tuple".\n' + '* "TypeError" will be raised if nonempty *__slots__* are ' + 'defined for a\n' + ' class derived from a ""variable-length" built-in type" ' + 'such as\n' + ' "int", "bytes", and "tuple".\n' '\n' '* Any non-string *iterable* may be assigned to ' '*__slots__*.\n' @@ -3072,7 +3073,7 @@ 'AS\n' 'pattern binds the subject to the name on the right of the as ' 'keyword\n' - 'and succeeds. "capture_pattern" cannot be a a "_".\n' + 'and succeeds. "capture_pattern" cannot be a "_".\n' '\n' 'In simple terms "P as NAME" will match with "P", and on success ' 'it\n' @@ -4675,7 +4676,7 @@ 'scripts. For\n' 'example:\n' '\n' - ' python3 -m pdb myscript.py\n' + ' python -m pdb myscript.py\n' '\n' 'When invoked as a script, pdb will automatically enter ' 'post-mortem\n' @@ -4695,7 +4696,7 @@ '\n' 'New in version 3.7: "pdb.py" now accepts a "-m" option that ' 'execute\n' - 'modules similar to the way "python3 -m" does. As with a script, ' + 'modules similar to the way "python -m" does. As with a script, ' 'the\n' 'debugger will pause execution just before the first line of the\n' 'module.\n' @@ -4759,8 +4760,8 @@ 'object)\n' ' under debugger control. When "runeval()" returns, it returns ' 'the\n' - ' value of the expression. Otherwise this function is similar ' - 'to\n' + ' value of the *expression*. Otherwise this function is ' + 'similar to\n' ' "run()".\n' '\n' 'pdb.runcall(function, *args, **kwds)\n' @@ -4799,7 +4800,7 @@ 'pdb.pm()\n' '\n' ' Enter post-mortem debugging of the traceback found in\n' - ' "sys.last_exc".\n' + ' "sys.last_traceback".\n' '\n' 'The "run*" functions and "set_trace()" are aliases for ' 'instantiating\n' @@ -5022,14 +5023,15 @@ 'ignore bpnumber [count]\n' '\n' ' Set the ignore count for the given breakpoint number. If ' - 'count is\n' - ' omitted, the ignore count is set to 0. A breakpoint becomes ' - 'active\n' - ' when the ignore count is zero. When non-zero, the count is\n' - ' decremented each time the breakpoint is reached and the ' - 'breakpoint\n' - ' is not disabled and any associated condition evaluates to ' - 'true.\n' + '*count*\n' + ' is omitted, the ignore count is set to 0. A breakpoint ' + 'becomes\n' + ' active when the ignore count is zero. When non-zero, the ' + '*count*\n' + ' is decremented each time the breakpoint is reached and the\n' + ' breakpoint is not disabled and any associated condition ' + 'evaluates\n' + ' to true.\n' '\n' 'condition bpnumber [condition]\n' '\n' @@ -5079,7 +5081,7 @@ ' breakpoint?which could have its own command list, leading to\n' ' ambiguities about which list to execute.\n' '\n' - ' If you use the ?silent? command in the command list, the ' + ' If you use the "silent" command in the command list, the ' 'usual\n' ' message about stopping at a breakpoint is not printed. This ' 'may be\n' @@ -5114,11 +5116,10 @@ 'number\n' ' greater than the current one is reached.\n' '\n' - ' With a line number, continue execution until a line with a ' - 'number\n' - ' greater or equal to that is reached. In both cases, also ' - 'stop when\n' - ' the current frame returns.\n' + ' With *lineno*, continue execution until a line with a number\n' + ' greater or equal to *lineno* is reached. In both cases, also ' + 'stop\n' + ' when the current frame returns.\n' '\n' ' Changed in version 3.2: Allow giving an explicit line ' 'number.\n' @@ -5182,9 +5183,8 @@ '\n' 'p expression\n' '\n' - ' Evaluate the *expression* in the current context and print ' - 'its\n' - ' value.\n' + ' Evaluate *expression* in the current context and print its ' + 'value.\n' '\n' ' Note:\n' '\n' @@ -5194,26 +5194,26 @@ '\n' 'pp expression\n' '\n' - ' Like the "p" command, except the value of the expression is ' + ' Like the "p" command, except the value of *expression* is ' 'pretty-\n' ' printed using the "pprint" module.\n' '\n' 'whatis expression\n' '\n' - ' Print the type of the *expression*.\n' + ' Print the type of *expression*.\n' '\n' 'source expression\n' '\n' - ' Try to get source code for the given object and display it.\n' + ' Try to get source code of *expression* and display it.\n' '\n' ' New in version 3.2.\n' '\n' 'display [expression]\n' '\n' - ' Display the value of the expression if it changed, each time\n' + ' Display the value of *expression* if it changed, each time\n' ' execution stops in the current frame.\n' '\n' - ' Without expression, list all display expressions for the ' + ' Without *expression*, list all display expressions for the ' 'current\n' ' frame.\n' '\n' @@ -5221,10 +5221,10 @@ '\n' 'undisplay [expression]\n' '\n' - ' Do not display the expression any more in the current frame.\n' - ' Without expression, clear all display expressions for the ' - 'current\n' - ' frame.\n' + ' Do not display *expression* anymore in the current frame. ' + 'Without\n' + ' *expression*, clear all display expressions for the current ' + 'frame.\n' '\n' ' New in version 3.2.\n' '\n' @@ -5240,16 +5240,16 @@ '\n' 'alias [name [command]]\n' '\n' - ' Create an alias called *name* that executes *command*. The ' - 'command\n' - ' must *not* be enclosed in quotes. Replaceable parameters can ' - 'be\n' - ' indicated by "%1", "%2", and so on, while "%*" is replaced by ' - 'all\n' - ' the parameters. If no command is given, the current alias ' - 'for\n' - ' *name* is shown. If no arguments are given, all aliases are ' - 'listed.\n' + ' Create an alias called *name* that executes *command*. The\n' + ' *command* must *not* be enclosed in quotes. Replaceable ' + 'parameters\n' + ' can be indicated by "%1", "%2", and so on, while "%*" is ' + 'replaced\n' + ' by all the parameters. If *command* is omitted, the current ' + 'alias\n' + ' for *name* is shown. If no arguments are given, all aliases ' + 'are\n' + ' listed.\n' '\n' ' Aliases may be nested and can contain anything that can be ' 'legally\n' @@ -5268,14 +5268,14 @@ ' in the ".pdbrc" file):\n' '\n' ' # Print instance variables (usage "pi classInst")\n' - ' alias pi for k in %1.__dict__.keys(): ' - 'print("%1.",k,"=",%1.__dict__[k])\n' + ' alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = ' + '{%1.__dict__[k]}")\n' ' # Print instance variables in self\n' ' alias ps pi self\n' '\n' 'unalias name\n' '\n' - ' Delete the specified alias.\n' + ' Delete the specified alias *name*.\n' '\n' '! statement\n' '\n' @@ -5295,12 +5295,13 @@ 'run [args ...]\n' 'restart [args ...]\n' '\n' - ' Restart the debugged Python program. If an argument is ' - 'supplied,\n' - ' it is split with "shlex" and the result is used as the new\n' - ' "sys.argv". History, breakpoints, actions and debugger ' - 'options are\n' - ' preserved. "restart" is an alias for "run".\n' + ' Restart the debugged Python program. If *args* is supplied, ' + 'it is\n' + ' split with "shlex" and the result is used as the new ' + '"sys.argv".\n' + ' History, breakpoints, actions and debugger options are ' + 'preserved.\n' + ' "restart" is an alias for "run".\n' '\n' 'q(uit)\n' '\n' @@ -5309,11 +5310,11 @@ '\n' 'debug code\n' '\n' - ' Enter a recursive debugger that steps through the code ' - 'argument\n' - ' (which is an arbitrary expression or statement to be executed ' - 'in\n' - ' the current environment).\n' + ' Enter a recursive debugger that steps through *code* (which ' + 'is an\n' + ' arbitrary expression or statement to be executed in the ' + 'current\n' + ' environment).\n' '\n' 'retval\n' '\n' @@ -6170,7 +6171,8 @@ 'The general form of a *standard format specifier* is:\n' '\n' ' format_spec ::= ' - '[[fill]align][sign][z][#][0][width][grouping_option][.precision][type]\n' + '[[fill]align][sign]["z"]["#"]["0"][width][grouping_option]["." ' + 'precision][type]\n' ' fill ::= \n' ' align ::= "<" | ">" | "=" | "^"\n' ' sign ::= "+" | "-" | " "\n' @@ -9981,10 +9983,11 @@ 'future, a\n' ' check may be added to prevent this.\n' '\n' - '* Nonempty *__slots__* does not work for classes derived ' - 'from\n' - ' ?variable-length? built-in types such as "int", "bytes" ' - 'and "tuple".\n' + '* "TypeError" will be raised if nonempty *__slots__* are ' + 'defined for a\n' + ' class derived from a ""variable-length" built-in type" ' + 'such as\n' + ' "int", "bytes", and "tuple".\n' '\n' '* Any non-string *iterable* may be assigned to *__slots__*.\n' '\n' @@ -13691,11 +13694,10 @@ ' compiled; "co_firstlineno" is the first line number of the\n' ' function; "co_lnotab" is a string encoding the mapping from\n' ' bytecode offsets to line numbers (for details see the source\n' - ' code of the interpreter); "co_stacksize" is the required ' - 'stack\n' - ' size; "co_flags" is an integer encoding a number of flags ' - 'for\n' - ' the interpreter.\n' + ' code of the interpreter, is deprecated since 3.12 and may be\n' + ' removed in 3.14); "co_stacksize" is the required stack size;\n' + ' "co_flags" is an integer encoding a number of flags for the\n' + ' interpreter.\n' '\n' ' The following flag bits are defined for "co_flags": bit ' '"0x04"\n' @@ -13858,7 +13860,7 @@ 'if\n' ' the interpreter is interactive, it is also made available to ' 'the\n' - ' user as "sys.last_exc".\n' + ' user as "sys.last_traceback".\n' '\n' ' For explicitly created tracebacks, it is up to the creator ' 'of\n' diff --git a/Misc/NEWS.d/3.12.0a7.rst b/Misc/NEWS.d/3.12.0a7.rst new file mode 100644 index 000000000000..8f078e50823a --- /dev/null +++ b/Misc/NEWS.d/3.12.0a7.rst @@ -0,0 +1,745 @@ +.. date: 2023-03-31-12-22-25 +.. gh-issue: 102192 +.. nonce: gYxJP_ +.. release date: 2023-04-04 +.. section: Core and Builtins + +Deprecated ``_PyErr_ChainExceptions`` in favour of +``_PyErr_ChainExceptions1``. + +.. + +.. date: 2023-03-24-02-50-33 +.. gh-issue: 89987 +.. nonce: oraTzh +.. section: Core and Builtins + +Reduce the number of inline :opcode:`CACHE` entries for +:opcode:`BINARY_SUBSCR`. + +.. + +.. date: 2023-03-21-00-46-36 +.. gh-issue: 102859 +.. nonce: PRkGca +.. section: Core and Builtins + +Removed :opcode:`JUMP_IF_FALSE_OR_POP` and :opcode:`JUMP_IF_TRUE_OR_POP` +instructions. + +.. + +.. date: 2023-03-18-02-36-39 +.. gh-issue: 101975 +.. nonce: HwMR1d +.. section: Core and Builtins + +Fixed ``stacktop`` value on tracing entries to avoid corruption on garbage +collection. + +.. + +.. date: 2023-03-17-13-43-34 +.. gh-issue: 102778 +.. nonce: ANDv8I +.. section: Core and Builtins + +Add :data:`sys.last_exc` and deprecate :data:`sys.last_type`, +:data:`sys.last_value` and :data:`sys.last_traceback`, which hold the same +information in its legacy form. + +.. + +.. date: 2023-03-17-12-09-45 +.. gh-issue: 100982 +.. nonce: Pf_BI6 +.. section: Core and Builtins + +Replace all occurrences of ``COMPARE_AND_BRANCH`` with :opcode:`COMPARE_OP`. + +.. + +.. date: 2023-03-16-17-24-44 +.. gh-issue: 102701 +.. nonce: iNGVaS +.. section: Core and Builtins + +Fix overflow when creating very large dict. + +.. + +.. date: 2023-03-16-14-44-29 +.. gh-issue: 102755 +.. nonce: j1GxlV +.. section: Core and Builtins + +Add :c:func:`PyErr_DisplayException` which takes just an exception instance, +to replace the legacy :c:func:`PyErr_Display` which takes the ``(typ, exc, +tb)`` triplet. + +.. + +.. date: 2023-03-14-00-11-46 +.. gh-issue: 102594 +.. nonce: BjU-m2 +.. section: Core and Builtins + +Add note to exception raised in ``PyErr_SetObject`` when normalization +fails. + +.. + +.. date: 2023-03-09-13-57-35 +.. gh-issue: 90997 +.. nonce: J-Yhn2 +.. section: Core and Builtins + +Shrink the number of inline :opcode:`CACHE` entries used by +:opcode:`LOAD_GLOBAL`. + +.. + +.. date: 2023-03-08-08-37-36 +.. gh-issue: 102491 +.. nonce: SFvvsC +.. section: Core and Builtins + +Improve import time of ``platform`` by removing IronPython version parsing. +The IronPython version parsing was not functional (see +https://github.com/IronLanguages/ironpython3/issues/1667). + +.. + +.. date: 2023-03-06-10-02-22 +.. gh-issue: 101291 +.. nonce: 0FT2QS +.. section: Core and Builtins + +Rearrage bits in first field (after header) of PyLongObject. * Bits 0 and 1: +1 - sign. I.e. 0 for positive numbers, 1 for zero and 2 for negative +numbers. * Bit 2 reserved (probably for the immortal bit) * Bits 3+ the +unsigned size. + +This makes a few operations slightly more efficient, and will enable a more +compact and faster 2s-complement representation of most ints in future. + +.. + +.. date: 2023-03-04-06-48-34 +.. gh-issue: 102397 +.. nonce: ACJaOf +.. section: Core and Builtins + +Fix segfault from race condition in signal handling during garbage +collection. Patch by Kumar Aditya. + +.. + +.. date: 2023-03-03-23-21-16 +.. gh-issue: 102406 +.. nonce: XLqYO3 +.. section: Core and Builtins + +:mod:`codecs` encoding/decoding errors now get the context information +(which operation and which codecs) attached as :pep:`678` notes instead of +through chaining a new instance of the exception. + +.. + +.. date: 2023-03-02-13-49-21 +.. gh-issue: 102281 +.. nonce: QCuu2N +.. section: Core and Builtins + +Fix potential nullptr dereference and use of uninitialized memory in +fileutils. Patch by Max Bachmann. + +.. + +.. date: 2023-02-27-15-48-31 +.. gh-issue: 102300 +.. nonce: 8o-_Mt +.. section: Core and Builtins + +Reuse operands with refcount of 1 in float specializations of BINARY_OP. + +.. + +.. date: 2023-02-26-13-12-55 +.. gh-issue: 102213 +.. nonce: fTH8X7 +.. section: Core and Builtins + +Fix performance loss when accessing an object's attributes with +``__getattr__`` defined. + +.. + +.. date: 2023-02-26-11-43-56 +.. gh-issue: 102255 +.. nonce: cRnI5x +.. section: Core and Builtins + +Improve build support for the Xbox. Patch by Max Bachmann. + +.. + +.. date: 2023-02-21-23-42-39 +.. gh-issue: 102027 +.. nonce: fQARG0 +.. section: Core and Builtins + +Fix SSE2 and SSE3 detection in ``_blake2`` internal module. Patch by Max +Bachmann. + +.. + +.. date: 2023-02-21-17-22-06 +.. gh-issue: 101865 +.. nonce: fwrTOA +.. section: Core and Builtins + +Deprecate ``co_lnotab`` in code objects, schedule it for removal in Python +3.14 + +.. + +.. bpo: 1635741 +.. date: 2020-07-04-09-04-41 +.. nonce: ZsP31Y +.. section: Core and Builtins + +Adapt :mod:`!_pickle` to :pep:`687`. Patch by Mohamed Koubaa and Erlend +Aasland. + +.. + +.. date: 2023-03-28-15-12-53 +.. gh-issue: 103085 +.. nonce: DqNehf +.. section: Library + +Pure python :func:`locale.getencoding()` will not warn deprecation. + +.. + +.. date: 2023-03-28-05-14-59 +.. gh-issue: 103068 +.. nonce: YQTmrA +.. section: Library + +It's no longer possible to register conditional breakpoints in +:class:`~pdb.Pdb` that raise :exc:`SyntaxError`. Patch by Tian Gao. + +.. + +.. date: 2023-03-27-19-21-51 +.. gh-issue: 102549 +.. nonce: NQ6Nlv +.. section: Library + +Don't ignore exceptions in member type creation. + +.. + +.. date: 2023-03-27-15-01-16 +.. gh-issue: 103056 +.. nonce: -Efh5Q +.. section: Library + +Ensure final ``_generate_next_value_`` is a ``staticmethod``. + +.. + +.. date: 2023-03-26-20-54-57 +.. gh-issue: 103046 +.. nonce: xBlA2l +.. section: Library + +Display current line label correctly in :mod:`dis` when ``show_caches`` is +False and ``lasti`` points to a CACHE entry. + +.. + +.. date: 2023-03-25-16-57-18 +.. gh-issue: 102433 +.. nonce: L-7x2Q +.. section: Library + +:func:`isinstance` checks against :func:`runtime-checkable protocols +` now use :func:`inspect.getattr_static` rather +than :func:`hasattr` to lookup whether attributes exist. This means that +descriptors and :meth:`~object.__getattr__` methods are no longer +unexpectedly evaluated during ``isinstance()`` checks against +runtime-checkable protocols. However, it may also mean that some objects +which used to be considered instances of a runtime-checkable protocol may no +longer be considered instances of that protocol on Python 3.12+, and vice +versa. Most users are unlikely to be affected by this change. Patch by Alex +Waygood. + +.. + +.. date: 2023-03-25-02-08-05 +.. gh-issue: 103023 +.. nonce: Qfn7Hl +.. section: Library + +It's no longer possible to register expressions to display in +:class:`~pdb.Pdb` that raise :exc:`SyntaxError`. Patch by Tian Gao. + +.. + +.. date: 2023-03-23-13-34-33 +.. gh-issue: 102947 +.. nonce: cTwcpU +.. section: Library + +Improve traceback when :func:`dataclasses.fields` is called on a +non-dataclass. Patch by Alex Waygood + +.. + +.. date: 2023-03-22-16-15-18 +.. gh-issue: 102780 +.. nonce: NEcljy +.. section: Library + +The :class:`asyncio.Timeout` context manager now works reliably even when +performing cleanup due to task cancellation. Previously it could raise a +:exc:`~asyncio.CancelledError` instead of an :exc:`~asyncio.TimeoutError` in +such cases. + +.. + +.. date: 2023-03-21-15-17-07 +.. gh-issue: 102871 +.. nonce: U9mchn +.. section: Library + +Remove support for obsolete browsers from :mod:`webbrowser`. Removed +browsers include Grail, Mosaic, Netscape, Galeon, Skipstone, Iceape, +Firebird, and Firefox versions 35 and below. + +.. + +.. date: 2023-03-20-12-21-19 +.. gh-issue: 102839 +.. nonce: RjRi12 +.. section: Library + +Improve performance of :func:`math.log` arguments handling by removing the +argument clinic. + +.. + +.. date: 2023-03-19-15-30-59 +.. gh-issue: 102828 +.. nonce: NKClXg +.. section: Library + +Add the ``onexc`` arg to :func:`shutil.rmtree`, which is like ``onerror`` +but expects an exception instance rather than an exc_info tuple. Deprecate +``onerror``. + +.. + +.. date: 2023-03-18-14-59-21 +.. gh-issue: 88965 +.. nonce: kA70Km +.. section: Library + +typing: Fix a bug relating to substitution in custom classes generic over a +:class:`~typing.ParamSpec`. Previously, if the ``ParamSpec`` was substituted +with a parameters list that itself contained a :class:`~typing.TypeVar`, the +``TypeVar`` in the parameters list could not be subsequently substituted. +This is now fixed. + +Patch by Nikita Sobolev. + +.. + +.. date: 2023-03-17-19-14-26 +.. gh-issue: 76846 +.. nonce: KEamjK +.. section: Library + +Fix issue where ``__new__()`` and ``__init__()`` methods of +:class:`pathlib.PurePath` and :class:`~pathlib.Path` subclasses were not +called in some circumstances. + +.. + +.. date: 2023-03-16-16-43-04 +.. gh-issue: 78530 +.. nonce: Lr8eq_ +.. section: Library + +:func:`asyncio.wait` now accepts generators yielding tasks. Patch by Kumar +Aditya. + +.. + +.. date: 2023-03-16-08-17-29 +.. gh-issue: 102748 +.. nonce: WNACpI +.. section: Library + +:func:`asyncio.iscoroutine` now returns ``False`` for generators as +:mod:`asyncio` does not support legacy generator-based coroutines. Patch by +Kumar Aditya. + +.. + +.. date: 2023-03-13-18-27-00 +.. gh-issue: 102670 +.. nonce: GyoThv +.. section: Library + +Optimized fmean(), correlation(), covariance(), and linear_regression() +using the new math.sumprod() function. + +.. + +.. date: 2023-03-13-12-05-55 +.. gh-issue: 102615 +.. nonce: NcA_ZL +.. section: Library + +Typing: Improve the ``repr`` of generic aliases for classes generic over a +:class:`~typing.ParamSpec`. (Use square brackets to represent a parameter +list.) + +.. + +.. date: 2023-03-10-13-51-21 +.. gh-issue: 100112 +.. nonce: VHh4mw +.. section: Library + +:meth:`asyncio.Task.get_coro` now always returns a coroutine when wrapping +an awaitable object. Patch by Kumar Aditya. + +.. + +.. date: 2023-03-10-13-21-16 +.. gh-issue: 102578 +.. nonce: -gujoI +.. section: Library + +Speed up setting or deleting mutable attributes on non-dataclass subclasses +of frozen dataclasses. Due to the implementation of ``__setattr__`` and +``__delattr__`` for frozen dataclasses, this previously had a time +complexity of ``O(n)``. It now has a time complexity of ``O(1)``. + +.. + +.. date: 2023-03-08-23-08-38 +.. gh-issue: 102519 +.. nonce: wlcsFI +.. section: Library + +Add :func:`os.listdrives`, :func:`os.listvolumes` and :func:`os.listmounts` +functions on Windows for enumerating drives, volumes and mount points + +.. + +.. date: 2023-03-04-20-58-29 +.. gh-issue: 74468 +.. nonce: Ac5Ew_ +.. section: Library + +Attribute name of the extracted :mod:`tarfile` file object now holds +filename of itself rather than of the archive it is contained in. Patch by +Oleg Iarygin. + +.. + +.. date: 2023-03-03-19-53-08 +.. gh-issue: 102378 +.. nonce: kRdOZc +.. section: Library + +Private helper method ``inspect._signature_strip_non_python_syntax`` will no +longer strip ``/`` from the input string. + +.. + +.. date: 2023-02-26-17-29-57 +.. gh-issue: 79940 +.. nonce: SAfmAy +.. section: Library + +Add :func:`inspect.getasyncgenstate` and :func:`inspect.getasyncgenlocals`. +Patch by Thomas Krennwallner. + +.. + +.. date: 2023-02-21-11-56-16 +.. gh-issue: 102103 +.. nonce: Dj0WEj +.. section: Library + +Add ``module`` argument to :func:`dataclasses.make_dataclass` and make +classes produced by it pickleable. + +.. + +.. date: 2023-02-20-16-47-56 +.. gh-issue: 102069 +.. nonce: FS7f1j +.. section: Library + +Fix ``__weakref__`` descriptor generation for custom dataclasses. + +.. + +.. date: 2023-02-19-01-49-46 +.. gh-issue: 102038 +.. nonce: n3if3D +.. section: Library + +Skip a ``stat`` in :mod:`site` if we have already found a ``pyvenv.cfg`` + +.. + +.. date: 2023-02-18-23-03-50 +.. gh-issue: 98886 +.. nonce: LkKGWv +.. section: Library + +Fix issues when defining dataclasses that have fields with specific +underscore names that aren't clearly reserved by :mod:`dataclasses`. + +.. + +.. date: 2023-02-09-19-40-41 +.. gh-issue: 101673 +.. nonce: mX-Ppq +.. section: Library + +Fix a :mod:`pdb` bug where ``ll`` clears the changes to local variables. + +.. + +.. date: 2023-01-27-14-51-07 +.. gh-issue: 101313 +.. nonce: 10AEXh +.. section: Library + +Added -h and --help arguments to the webbrowser CLI + +.. + +.. date: 2022-12-20-10-55-14 +.. gh-issue: 100372 +.. nonce: utfP65 +.. section: Library + +:meth:`ssl.SSLContext.load_verify_locations` no longer incorrectly accepts +some cases of trailing data when parsing DER. + +.. + +.. date: 2022-12-16-10-27-58 +.. gh-issue: 89727 +.. nonce: y64ZLM +.. section: Library + +Fix pathlib.Path.walk RecursionError on deep directory trees by rewriting it +using iteration instead of recursion. + +.. + +.. date: 2022-12-09-11-21-38 +.. gh-issue: 100131 +.. nonce: v863yR +.. section: Library + +Added an optional ``delete`` keyword argument to +:class:`tempfile.TemporaryDirectory`. + +.. + +.. date: 2022-11-24-13-23-07 +.. gh-issue: 48330 +.. nonce: 6uAX9F +.. section: Library + +Added ``--durations`` command line option, showing the N slowest test cases. +:class:`unittest.TextTestRunner` and :class:`unittest.TextTestResult` +constructors accept a new *durations* keyword argument. Subclasses should +take this into account or accept ``**kwargs``. Added +:meth:`unittest.TestResult.addDuration` method and +:attr:`unittest.TestResult.collectedDurations` attribute. + +(Contributed by Giampaolo Rodola) + +.. + +.. date: 2022-10-10-19-14-51 +.. gh-issue: 98169 +.. nonce: DBWIxL +.. section: Library + +Fix :func:`dataclasses.astuple` crash when :class:`collections.defaultdict` +is present in the attributes. + +.. + +.. date: 2022-09-19-08-12-58 +.. gh-issue: 96931 +.. nonce: x0WQhh +.. section: Library + +Fix incorrect results from :meth:`ssl.SSLSocket.shared_ciphers` + +.. + +.. date: 2022-07-30-23-01-43 +.. gh-issue: 95495 +.. nonce: RA-q1d +.. section: Library + +When built against OpenSSL 3.0, the :mod:`ssl` module had a bug where it +reported unauthenticated EOFs (i.e. without close_notify) as a clean +TLS-level EOF. It now raises :exc:`~ssl.SSLEOFError`, matching the behavior +in previous versions of OpenSSL. The :attr:`~ssl.SSLContext.options` +attribute on :class:`~ssl.SSLContext` also no longer includes +:data:`~ssl.OP_IGNORE_UNEXPECTED_EOF` by default. This option may be set to +specify the previous OpenSSL 3.0 behavior. + +.. + +.. date: 2022-07-09-13-07-30 +.. gh-issue: 94684 +.. nonce: nV5yno +.. section: Library + +Now :func:`uuid.uuid3` and :func:`uuid.uuid5` functions support +:class:`bytes` objects as their *name* argument. + +.. + +.. date: 2022-06-30-21-28-41 +.. gh-issue: 94440 +.. nonce: LtgX0d +.. section: Library + +Fix a :mod:`concurrent.futures.process` bug where ``ProcessPoolExecutor`` +shutdown could hang after a future has been quickly submitted and canceled. + +.. + +.. date: 2022-04-11-18-34-33 +.. gh-issue: 72346 +.. nonce: pC7gnM +.. section: Library + +Added deprecation warning to *isdst* parameter of +:func:`email.utils.localtime`. + +.. + +.. bpo: 36305 +.. date: 2019-03-15-22-50-27 +.. nonce: Pbkv6u +.. section: Library + +Fix handling of Windows filenames that resemble drives, such as ``./a:b``, +in :mod:`pathlib`. + +.. + +.. date: 2023-03-29-14-51-39 +.. gh-issue: 103112 +.. nonce: XgGSEO +.. section: Documentation + +Add docstring to :meth:`http.client.HTTPResponse.read` to fix ``pydoc`` +output. + +.. + +.. date: 2023-03-23-23-25-18 +.. gh-issue: 102980 +.. nonce: Zps4QF +.. section: Tests + +Improve test coverage on :mod:`pdb`. + +.. + +.. date: 2023-03-08-13-54-20 +.. gh-issue: 102537 +.. nonce: Vfplpb +.. section: Tests + +Adjust the error handling strategy in +``test_zoneinfo.TzPathTest.python_tzpath_context``. Patch by Paul Ganssle. + +.. + +.. date: 2023-01-27-18-10-40 +.. gh-issue: 101377 +.. nonce: IJGpqh +.. section: Tests + +Improved test_locale_calendar_formatweekday of calendar. + +.. + +.. date: 2023-03-23-20-58-56 +.. gh-issue: 102973 +.. nonce: EaJUrw +.. section: Build + +Add a dev container (along with accompanying Dockerfile) for development +purposes. + +.. + +.. date: 2023-03-15-02-03-39 +.. gh-issue: 102711 +.. nonce: zTkjts +.. section: Build + +Fix ``-Wstrict-prototypes`` compiler warnings. + +.. + +.. date: 2023-03-14-10-52-43 +.. gh-issue: 102690 +.. nonce: sbXtqk +.. section: Windows + +Update :mod:`webbrowser` to fall back to Microsoft Edge instead of Internet +Explorer. + +.. + +.. date: 2023-02-22-17-26-10 +.. gh-issue: 99726 +.. nonce: 76t957 +.. section: Windows + +Improves correctness of stat results for Windows, and uses faster API when +available + +.. + +.. date: 2023-03-21-01-27-07 +.. gh-issue: 102809 +.. nonce: 2F1Byz +.. section: Tools/Demos + +``Misc/gdbinit`` was removed. + +.. + +.. date: 2023-02-18-00-55-14 +.. gh-issue: 102013 +.. nonce: 83mrtI +.. section: C API + +Add a new (unstable) C-API function for iterating over GC'able objects using +a callback: ``PyUnstable_VisitObjects``. diff --git a/Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst b/Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst deleted file mode 100644 index 511843968777..000000000000 --- a/Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst +++ /dev/null @@ -1 +0,0 @@ -Fix ``-Wstrict-prototypes`` compiler warnings. diff --git a/Misc/NEWS.d/next/Build/2023-03-23-20-58-56.gh-issue-102973.EaJUrw.rst b/Misc/NEWS.d/next/Build/2023-03-23-20-58-56.gh-issue-102973.EaJUrw.rst deleted file mode 100644 index 38b02391266f..000000000000 --- a/Misc/NEWS.d/next/Build/2023-03-23-20-58-56.gh-issue-102973.EaJUrw.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add a dev container (along with accompanying Dockerfile) for development -purposes. diff --git a/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst b/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst deleted file mode 100644 index 0350237ebc73..000000000000 --- a/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst +++ /dev/null @@ -1 +0,0 @@ -Add a new (unstable) C-API function for iterating over GC'able objects using a callback: ``PyUnstable_VisitObjects``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-07-04-09-04-41.bpo-1635741.ZsP31Y.rst b/Misc/NEWS.d/next/Core and Builtins/2020-07-04-09-04-41.bpo-1635741.ZsP31Y.rst deleted file mode 100644 index 9f9c8121bea5..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-07-04-09-04-41.bpo-1635741.ZsP31Y.rst +++ /dev/null @@ -1 +0,0 @@ -Adapt :mod:`!_pickle` to :pep:`687`. Patch by Mohamed Koubaa and Erlend Aasland. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-21-17-22-06.gh-issue-101865.fwrTOA.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-21-17-22-06.gh-issue-101865.fwrTOA.rst deleted file mode 100644 index 876cc223a0e7..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-21-17-22-06.gh-issue-101865.fwrTOA.rst +++ /dev/null @@ -1,2 +0,0 @@ -Deprecate ``co_lnotab`` in code objects, schedule it for removal in Python -3.14 diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst deleted file mode 100644 index 42d96b54677e..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix SSE2 and SSE3 detection in ``_blake2`` internal module. Patch by Max -Bachmann. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-26-11-43-56.gh-issue-102255.cRnI5x.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-26-11-43-56.gh-issue-102255.cRnI5x.rst deleted file mode 100644 index daabc3c15f6e..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-26-11-43-56.gh-issue-102255.cRnI5x.rst +++ /dev/null @@ -1 +0,0 @@ -Improve build support for the Xbox. Patch by Max Bachmann. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-26-13-12-55.gh-issue-102213.fTH8X7.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-26-13-12-55.gh-issue-102213.fTH8X7.rst deleted file mode 100644 index 997bef226e71..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-26-13-12-55.gh-issue-102213.fTH8X7.rst +++ /dev/null @@ -1 +0,0 @@ -Fix performance loss when accessing an object's attributes with ``__getattr__`` defined. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-27-15-48-31.gh-issue-102300.8o-_Mt.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-27-15-48-31.gh-issue-102300.8o-_Mt.rst deleted file mode 100644 index 4227014582b7..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-27-15-48-31.gh-issue-102300.8o-_Mt.rst +++ /dev/null @@ -1 +0,0 @@ -Reuse operands with refcount of 1 in float specializations of BINARY_OP. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst deleted file mode 100644 index b0269dd3d92b..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst +++ /dev/null @@ -1 +0,0 @@ -Fix potential nullptr dereference and use of uninitialized memory in fileutils. Patch by Max Bachmann. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-03-23-21-16.gh-issue-102406.XLqYO3.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-03-23-21-16.gh-issue-102406.XLqYO3.rst deleted file mode 100644 index e0d061c37299..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-03-23-21-16.gh-issue-102406.XLqYO3.rst +++ /dev/null @@ -1 +0,0 @@ -:mod:`codecs` encoding/decoding errors now get the context information (which operation and which codecs) attached as :pep:`678` notes instead of through chaining a new instance of the exception. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst deleted file mode 100644 index db0b3f32c2ec..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix segfault from race condition in signal handling during garbage collection. -Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst deleted file mode 100644 index 46f0f325f916..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst +++ /dev/null @@ -1,7 +0,0 @@ -Rearrage bits in first field (after header) of PyLongObject. -* Bits 0 and 1: 1 - sign. I.e. 0 for positive numbers, 1 for zero and 2 for negative numbers. -* Bit 2 reserved (probably for the immortal bit) -* Bits 3+ the unsigned size. - -This makes a few operations slightly more efficient, and will enable a more -compact and faster 2s-complement representation of most ints in future. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-08-08-37-36.gh-issue-102491.SFvvsC.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-08-08-37-36.gh-issue-102491.SFvvsC.rst deleted file mode 100644 index 5bdc9ed2f37a..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-08-08-37-36.gh-issue-102491.SFvvsC.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve import time of ``platform`` by removing IronPython version parsing. The IronPython version parsing -was not functional (see https://github.com/IronLanguages/ironpython3/issues/1667). diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-09-13-57-35.gh-issue-90997.J-Yhn2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-09-13-57-35.gh-issue-90997.J-Yhn2.rst deleted file mode 100644 index 723a4b9fa777..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-09-13-57-35.gh-issue-90997.J-Yhn2.rst +++ /dev/null @@ -1,2 +0,0 @@ -Shrink the number of inline :opcode:`CACHE` entries used by -:opcode:`LOAD_GLOBAL`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-14-00-11-46.gh-issue-102594.BjU-m2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-14-00-11-46.gh-issue-102594.BjU-m2.rst deleted file mode 100644 index 0b95b5ec98e8..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-14-00-11-46.gh-issue-102594.BjU-m2.rst +++ /dev/null @@ -1 +0,0 @@ -Add note to exception raised in ``PyErr_SetObject`` when normalization fails. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-16-14-44-29.gh-issue-102755.j1GxlV.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-16-14-44-29.gh-issue-102755.j1GxlV.rst deleted file mode 100644 index d09af8d060d4..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-16-14-44-29.gh-issue-102755.j1GxlV.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add :c:func:`PyErr_DisplayException` which takes just an exception instance, -to replace the legacy :c:func:`PyErr_Display` which takes the ``(typ, exc, -tb)`` triplet. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst deleted file mode 100644 index 4e1f31893377..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst +++ /dev/null @@ -1 +0,0 @@ -Fix overflow when creating very large dict. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst deleted file mode 100644 index 31a8660836c7..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst +++ /dev/null @@ -1 +0,0 @@ -Replace all occurrences of ``COMPARE_AND_BRANCH`` with :opcode:`COMPARE_OP`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst deleted file mode 100644 index b5da227afa5a..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add :data:`sys.last_exc` and deprecate :data:`sys.last_type`, :data:`sys.last_value` -and :data:`sys.last_traceback`, -which hold the same information in its legacy form. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst deleted file mode 100644 index 28c9a8465180..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed ``stacktop`` value on tracing entries to avoid corruption on garbage collection. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-21-00-46-36.gh-issue-102859.PRkGca.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-21-00-46-36.gh-issue-102859.PRkGca.rst deleted file mode 100644 index d2e2232c33cc..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-21-00-46-36.gh-issue-102859.PRkGca.rst +++ /dev/null @@ -1,2 +0,0 @@ -Removed :opcode:`JUMP_IF_FALSE_OR_POP` and :opcode:`JUMP_IF_TRUE_OR_POP` -instructions. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-24-02-50-33.gh-issue-89987.oraTzh.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-24-02-50-33.gh-issue-89987.oraTzh.rst deleted file mode 100644 index 507f68b0c5af..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-24-02-50-33.gh-issue-89987.oraTzh.rst +++ /dev/null @@ -1,2 +0,0 @@ -Reduce the number of inline :opcode:`CACHE` entries for -:opcode:`BINARY_SUBSCR`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-31-12-22-25.gh-issue-102192.gYxJP_.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-31-12-22-25.gh-issue-102192.gYxJP_.rst deleted file mode 100644 index 10dd72b1abc4..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-31-12-22-25.gh-issue-102192.gYxJP_.rst +++ /dev/null @@ -1,2 +0,0 @@ -Deprecated ``_PyErr_ChainExceptions`` in favour of -``_PyErr_ChainExceptions1``. diff --git a/Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst b/Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst deleted file mode 100644 index babc81509661..000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst +++ /dev/null @@ -1 +0,0 @@ -Add docstring to :meth:`http.client.HTTPResponse.read` to fix ``pydoc`` output. diff --git a/Misc/NEWS.d/next/Library/2019-03-15-22-50-27.bpo-36305.Pbkv6u.rst b/Misc/NEWS.d/next/Library/2019-03-15-22-50-27.bpo-36305.Pbkv6u.rst deleted file mode 100644 index d9360496ac24..000000000000 --- a/Misc/NEWS.d/next/Library/2019-03-15-22-50-27.bpo-36305.Pbkv6u.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix handling of Windows filenames that resemble drives, such as ``./a:b``, -in :mod:`pathlib`. diff --git a/Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-72346.pC7gnM.rst b/Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-72346.pC7gnM.rst deleted file mode 100644 index 149ddd706c35..000000000000 --- a/Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-72346.pC7gnM.rst +++ /dev/null @@ -1 +0,0 @@ -Added deprecation warning to *isdst* parameter of :func:`email.utils.localtime`. diff --git a/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst b/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst deleted file mode 100644 index 3eee82e59dfa..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a :mod:`concurrent.futures.process` bug where ``ProcessPoolExecutor`` shutdown -could hang after a future has been quickly submitted and canceled. diff --git a/Misc/NEWS.d/next/Library/2022-07-09-13-07-30.gh-issue-94684.nV5yno.rst b/Misc/NEWS.d/next/Library/2022-07-09-13-07-30.gh-issue-94684.nV5yno.rst deleted file mode 100644 index 1fa38c0044d3..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-09-13-07-30.gh-issue-94684.nV5yno.rst +++ /dev/null @@ -1 +0,0 @@ -Now :func:`uuid.uuid3` and :func:`uuid.uuid5` functions support :class:`bytes` objects as their *name* argument. diff --git a/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst b/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst deleted file mode 100644 index d0f4ccbdd3e3..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst +++ /dev/null @@ -1,7 +0,0 @@ -When built against OpenSSL 3.0, the :mod:`ssl` module had a bug where it -reported unauthenticated EOFs (i.e. without close_notify) as a clean TLS-level -EOF. It now raises :exc:`~ssl.SSLEOFError`, matching the behavior in previous -versions of OpenSSL. The :attr:`~ssl.SSLContext.options` attribute on -:class:`~ssl.SSLContext` also no longer includes -:data:`~ssl.OP_IGNORE_UNEXPECTED_EOF` by default. This option may be set to -specify the previous OpenSSL 3.0 behavior. diff --git a/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst b/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst deleted file mode 100644 index 766b1d4d477b..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst +++ /dev/null @@ -1 +0,0 @@ -Fix incorrect results from :meth:`ssl.SSLSocket.shared_ciphers` diff --git a/Misc/NEWS.d/next/Library/2022-10-10-19-14-51.gh-issue-98169.DBWIxL.rst b/Misc/NEWS.d/next/Library/2022-10-10-19-14-51.gh-issue-98169.DBWIxL.rst deleted file mode 100644 index 24c3aeecc83f..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-10-19-14-51.gh-issue-98169.DBWIxL.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :func:`dataclasses.astuple` crash when :class:`collections.defaultdict` -is present in the attributes. diff --git a/Misc/NEWS.d/next/Library/2022-11-24-13-23-07.gh-issue-48330.6uAX9F.rst b/Misc/NEWS.d/next/Library/2022-11-24-13-23-07.gh-issue-48330.6uAX9F.rst deleted file mode 100644 index 5b63a0a6b96d..000000000000 --- a/Misc/NEWS.d/next/Library/2022-11-24-13-23-07.gh-issue-48330.6uAX9F.rst +++ /dev/null @@ -1,8 +0,0 @@ -Added ``--durations`` command line option, showing the N slowest test cases. -:class:`unittest.TextTestRunner` and :class:`unittest.TextTestResult` -constructors accept a new *durations* keyword argument. Subclasses should take -this into account or accept ``**kwargs``. Added -:meth:`unittest.TestResult.addDuration` method and -:attr:`unittest.TestResult.collectedDurations` attribute. - -(Contributed by Giampaolo Rodola) diff --git a/Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst b/Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst deleted file mode 100644 index 07891f2c1e9e..000000000000 --- a/Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst +++ /dev/null @@ -1 +0,0 @@ -Added an optional ``delete`` keyword argument to :class:`tempfile.TemporaryDirectory`. diff --git a/Misc/NEWS.d/next/Library/2022-12-16-10-27-58.gh-issue-89727.y64ZLM.rst b/Misc/NEWS.d/next/Library/2022-12-16-10-27-58.gh-issue-89727.y64ZLM.rst deleted file mode 100644 index f9ac1475dceb..000000000000 --- a/Misc/NEWS.d/next/Library/2022-12-16-10-27-58.gh-issue-89727.y64ZLM.rst +++ /dev/null @@ -1 +0,0 @@ -Fix pathlib.Path.walk RecursionError on deep directory trees by rewriting it using iteration instead of recursion. diff --git a/Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst b/Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst deleted file mode 100644 index ec37aff5092c..000000000000 --- a/Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst +++ /dev/null @@ -1,2 +0,0 @@ -:meth:`ssl.SSLContext.load_verify_locations` no longer incorrectly accepts -some cases of trailing data when parsing DER. diff --git a/Misc/NEWS.d/next/Library/2023-01-27-14-51-07.gh-issue-101313.10AEXh.rst b/Misc/NEWS.d/next/Library/2023-01-27-14-51-07.gh-issue-101313.10AEXh.rst deleted file mode 100644 index 63d0a7286920..000000000000 --- a/Misc/NEWS.d/next/Library/2023-01-27-14-51-07.gh-issue-101313.10AEXh.rst +++ /dev/null @@ -1 +0,0 @@ -Added -h and --help arguments to the webbrowser CLI diff --git a/Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst b/Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst deleted file mode 100644 index 4e673ba98115..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a :mod:`pdb` bug where ``ll`` clears the changes to local variables. diff --git a/Misc/NEWS.d/next/Library/2023-02-18-23-03-50.gh-issue-98886.LkKGWv.rst b/Misc/NEWS.d/next/Library/2023-02-18-23-03-50.gh-issue-98886.LkKGWv.rst deleted file mode 100644 index 64e4d6eed2f6..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-18-23-03-50.gh-issue-98886.LkKGWv.rst +++ /dev/null @@ -1 +0,0 @@ -Fix issues when defining dataclasses that have fields with specific underscore names that aren't clearly reserved by :mod:`dataclasses`. diff --git a/Misc/NEWS.d/next/Library/2023-02-19-01-49-46.gh-issue-102038.n3if3D.rst b/Misc/NEWS.d/next/Library/2023-02-19-01-49-46.gh-issue-102038.n3if3D.rst deleted file mode 100644 index 40df20cb5960..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-19-01-49-46.gh-issue-102038.n3if3D.rst +++ /dev/null @@ -1 +0,0 @@ -Skip a ``stat`` in :mod:`site` if we have already found a ``pyvenv.cfg`` diff --git a/Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst b/Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst deleted file mode 100644 index 04c87e515cca..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst +++ /dev/null @@ -1 +0,0 @@ -Fix ``__weakref__`` descriptor generation for custom dataclasses. diff --git a/Misc/NEWS.d/next/Library/2023-02-21-11-56-16.gh-issue-102103.Dj0WEj.rst b/Misc/NEWS.d/next/Library/2023-02-21-11-56-16.gh-issue-102103.Dj0WEj.rst deleted file mode 100644 index feba433f5bee..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-21-11-56-16.gh-issue-102103.Dj0WEj.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add ``module`` argument to :func:`dataclasses.make_dataclass` and make -classes produced by it pickleable. diff --git a/Misc/NEWS.d/next/Library/2023-02-26-17-29-57.gh-issue-79940.SAfmAy.rst b/Misc/NEWS.d/next/Library/2023-02-26-17-29-57.gh-issue-79940.SAfmAy.rst deleted file mode 100644 index 31b8ead84332..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-26-17-29-57.gh-issue-79940.SAfmAy.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :func:`inspect.getasyncgenstate` and :func:`inspect.getasyncgenlocals`. -Patch by Thomas Krennwallner. diff --git a/Misc/NEWS.d/next/Library/2023-03-03-19-53-08.gh-issue-102378.kRdOZc.rst b/Misc/NEWS.d/next/Library/2023-03-03-19-53-08.gh-issue-102378.kRdOZc.rst deleted file mode 100644 index d30f65f30d10..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-03-19-53-08.gh-issue-102378.kRdOZc.rst +++ /dev/null @@ -1 +0,0 @@ -Private helper method ``inspect._signature_strip_non_python_syntax`` will no longer strip ``/`` from the input string. diff --git a/Misc/NEWS.d/next/Library/2023-03-04-20-58-29.gh-issue-74468.Ac5Ew_.rst b/Misc/NEWS.d/next/Library/2023-03-04-20-58-29.gh-issue-74468.Ac5Ew_.rst deleted file mode 100644 index 8fad551f3a4e..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-04-20-58-29.gh-issue-74468.Ac5Ew_.rst +++ /dev/null @@ -1,3 +0,0 @@ -Attribute name of the extracted :mod:`tarfile` file object now holds -filename of itself rather than of the archive it is contained in. -Patch by Oleg Iarygin. diff --git a/Misc/NEWS.d/next/Library/2023-03-08-23-08-38.gh-issue-102519.wlcsFI.rst b/Misc/NEWS.d/next/Library/2023-03-08-23-08-38.gh-issue-102519.wlcsFI.rst deleted file mode 100644 index f47e4f70b130..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-08-23-08-38.gh-issue-102519.wlcsFI.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :func:`os.listdrives`, :func:`os.listvolumes` and :func:`os.listmounts` -functions on Windows for enumerating drives, volumes and mount points diff --git a/Misc/NEWS.d/next/Library/2023-03-10-13-21-16.gh-issue-102578.-gujoI.rst b/Misc/NEWS.d/next/Library/2023-03-10-13-21-16.gh-issue-102578.-gujoI.rst deleted file mode 100644 index 7307148d9a81..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-10-13-21-16.gh-issue-102578.-gujoI.rst +++ /dev/null @@ -1,4 +0,0 @@ -Speed up setting or deleting mutable attributes on non-dataclass subclasses of -frozen dataclasses. Due to the implementation of ``__setattr__`` and -``__delattr__`` for frozen dataclasses, this previously had a time complexity -of ``O(n)``. It now has a time complexity of ``O(1)``. diff --git a/Misc/NEWS.d/next/Library/2023-03-10-13-51-21.gh-issue-100112.VHh4mw.rst b/Misc/NEWS.d/next/Library/2023-03-10-13-51-21.gh-issue-100112.VHh4mw.rst deleted file mode 100644 index eff77c40e30c..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-10-13-51-21.gh-issue-100112.VHh4mw.rst +++ /dev/null @@ -1 +0,0 @@ -:meth:`asyncio.Task.get_coro` now always returns a coroutine when wrapping an awaitable object. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2023-03-13-12-05-55.gh-issue-102615.NcA_ZL.rst b/Misc/NEWS.d/next/Library/2023-03-13-12-05-55.gh-issue-102615.NcA_ZL.rst deleted file mode 100644 index 333068369bc4..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-13-12-05-55.gh-issue-102615.NcA_ZL.rst +++ /dev/null @@ -1,3 +0,0 @@ -Typing: Improve the ``repr`` of generic aliases for classes generic over a -:class:`~typing.ParamSpec`. (Use square brackets to represent a parameter -list.) diff --git a/Misc/NEWS.d/next/Library/2023-03-13-18-27-00.gh-issue-102670.GyoThv.rst b/Misc/NEWS.d/next/Library/2023-03-13-18-27-00.gh-issue-102670.GyoThv.rst deleted file mode 100644 index 3de09f86754f..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-13-18-27-00.gh-issue-102670.GyoThv.rst +++ /dev/null @@ -1,2 +0,0 @@ -Optimized fmean(), correlation(), covariance(), and linear_regression() -using the new math.sumprod() function. diff --git a/Misc/NEWS.d/next/Library/2023-03-16-08-17-29.gh-issue-102748.WNACpI.rst b/Misc/NEWS.d/next/Library/2023-03-16-08-17-29.gh-issue-102748.WNACpI.rst deleted file mode 100644 index b1dc67f38fe8..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-16-08-17-29.gh-issue-102748.WNACpI.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`asyncio.iscoroutine` now returns ``False`` for generators as -:mod:`asyncio` does not support legacy generator-based coroutines. -Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2023-03-16-16-43-04.gh-issue-78530.Lr8eq_.rst b/Misc/NEWS.d/next/Library/2023-03-16-16-43-04.gh-issue-78530.Lr8eq_.rst deleted file mode 100644 index bdb46d08c5c4..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-16-16-43-04.gh-issue-78530.Lr8eq_.rst +++ /dev/null @@ -1 +0,0 @@ -:func:`asyncio.wait` now accepts generators yielding tasks. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2023-03-17-19-14-26.gh-issue-76846.KEamjK.rst b/Misc/NEWS.d/next/Library/2023-03-17-19-14-26.gh-issue-76846.KEamjK.rst deleted file mode 100644 index 9fba11f074ee..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-17-19-14-26.gh-issue-76846.KEamjK.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix issue where ``__new__()`` and ``__init__()`` methods of -:class:`pathlib.PurePath` and :class:`~pathlib.Path` subclasses were not -called in some circumstances. diff --git a/Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst b/Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst deleted file mode 100644 index 6e9642100cd8..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst +++ /dev/null @@ -1,7 +0,0 @@ -typing: Fix a bug relating to substitution in custom classes generic over a -:class:`~typing.ParamSpec`. Previously, if the ``ParamSpec`` was substituted -with a parameters list that itself contained a :class:`~typing.TypeVar`, the -``TypeVar`` in the parameters list could not be subsequently substituted. This -is now fixed. - -Patch by Nikita Sobolev. diff --git a/Misc/NEWS.d/next/Library/2023-03-19-15-30-59.gh-issue-102828.NKClXg.rst b/Misc/NEWS.d/next/Library/2023-03-19-15-30-59.gh-issue-102828.NKClXg.rst deleted file mode 100644 index be9b2bab24a3..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-19-15-30-59.gh-issue-102828.NKClXg.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add the ``onexc`` arg to :func:`shutil.rmtree`, which is like ``onerror`` -but expects an exception instance rather than an exc_info tuple. Deprecate -``onerror``. diff --git a/Misc/NEWS.d/next/Library/2023-03-20-12-21-19.gh-issue-102839.RjRi12.rst b/Misc/NEWS.d/next/Library/2023-03-20-12-21-19.gh-issue-102839.RjRi12.rst deleted file mode 100644 index 673b38974e4d..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-20-12-21-19.gh-issue-102839.RjRi12.rst +++ /dev/null @@ -1 +0,0 @@ -Improve performance of :func:`math.log` arguments handling by removing the argument clinic. diff --git a/Misc/NEWS.d/next/Library/2023-03-21-15-17-07.gh-issue-102871.U9mchn.rst b/Misc/NEWS.d/next/Library/2023-03-21-15-17-07.gh-issue-102871.U9mchn.rst deleted file mode 100644 index 3ef0e74d21ca..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-21-15-17-07.gh-issue-102871.U9mchn.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove support for obsolete browsers from :mod:`webbrowser`. -Removed browsers include Grail, Mosaic, Netscape, Galeon, Skipstone, -Iceape, Firebird, and Firefox versions 35 and below. diff --git a/Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst b/Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst deleted file mode 100644 index 2aaffe34b864..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst +++ /dev/null @@ -1,3 +0,0 @@ -The :class:`asyncio.Timeout` context manager now works reliably even when performing cleanup due -to task cancellation. Previously it could raise a -:exc:`~asyncio.CancelledError` instead of an :exc:`~asyncio.TimeoutError` in such cases. diff --git a/Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst b/Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst deleted file mode 100644 index b59c98203566..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve traceback when :func:`dataclasses.fields` is called on a -non-dataclass. Patch by Alex Waygood diff --git a/Misc/NEWS.d/next/Library/2023-03-25-02-08-05.gh-issue-103023.Qfn7Hl.rst b/Misc/NEWS.d/next/Library/2023-03-25-02-08-05.gh-issue-103023.Qfn7Hl.rst deleted file mode 100644 index e7958f6f0020..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-25-02-08-05.gh-issue-103023.Qfn7Hl.rst +++ /dev/null @@ -1,2 +0,0 @@ -It's no longer possible to register expressions to display in -:class:`~pdb.Pdb` that raise :exc:`SyntaxError`. Patch by Tian Gao. diff --git a/Misc/NEWS.d/next/Library/2023-03-25-16-57-18.gh-issue-102433.L-7x2Q.rst b/Misc/NEWS.d/next/Library/2023-03-25-16-57-18.gh-issue-102433.L-7x2Q.rst deleted file mode 100644 index a4de4b4448f3..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-25-16-57-18.gh-issue-102433.L-7x2Q.rst +++ /dev/null @@ -1,10 +0,0 @@ -:func:`isinstance` checks against :func:`runtime-checkable protocols -` now use :func:`inspect.getattr_static` rather -than :func:`hasattr` to lookup whether attributes exist. This means that -descriptors and :meth:`~object.__getattr__` methods are no longer -unexpectedly evaluated during ``isinstance()`` checks against -runtime-checkable protocols. However, it may also mean that some objects -which used to be considered instances of a runtime-checkable protocol may no -longer be considered instances of that protocol on Python 3.12+, and vice -versa. Most users are unlikely to be affected by this change. Patch by Alex -Waygood. diff --git a/Misc/NEWS.d/next/Library/2023-03-26-20-54-57.gh-issue-103046.xBlA2l.rst b/Misc/NEWS.d/next/Library/2023-03-26-20-54-57.gh-issue-103046.xBlA2l.rst deleted file mode 100644 index f9bd0a10056e..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-26-20-54-57.gh-issue-103046.xBlA2l.rst +++ /dev/null @@ -1 +0,0 @@ -Display current line label correctly in :mod:`dis` when ``show_caches`` is False and ``lasti`` points to a CACHE entry. diff --git a/Misc/NEWS.d/next/Library/2023-03-27-15-01-16.gh-issue-103056.-Efh5Q.rst b/Misc/NEWS.d/next/Library/2023-03-27-15-01-16.gh-issue-103056.-Efh5Q.rst deleted file mode 100644 index c892d8376503..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-27-15-01-16.gh-issue-103056.-Efh5Q.rst +++ /dev/null @@ -1 +0,0 @@ -Ensure final ``_generate_next_value_`` is a ``staticmethod``. diff --git a/Misc/NEWS.d/next/Library/2023-03-27-19-21-51.gh-issue-102549.NQ6Nlv.rst b/Misc/NEWS.d/next/Library/2023-03-27-19-21-51.gh-issue-102549.NQ6Nlv.rst deleted file mode 100644 index e4def038175b..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-27-19-21-51.gh-issue-102549.NQ6Nlv.rst +++ /dev/null @@ -1 +0,0 @@ -Don't ignore exceptions in member type creation. diff --git a/Misc/NEWS.d/next/Library/2023-03-28-05-14-59.gh-issue-103068.YQTmrA.rst b/Misc/NEWS.d/next/Library/2023-03-28-05-14-59.gh-issue-103068.YQTmrA.rst deleted file mode 100644 index 71c142c30f4e..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-28-05-14-59.gh-issue-103068.YQTmrA.rst +++ /dev/null @@ -1,2 +0,0 @@ -It's no longer possible to register conditional breakpoints in -:class:`~pdb.Pdb` that raise :exc:`SyntaxError`. Patch by Tian Gao. diff --git a/Misc/NEWS.d/next/Library/2023-03-28-15-12-53.gh-issue-103085.DqNehf.rst b/Misc/NEWS.d/next/Library/2023-03-28-15-12-53.gh-issue-103085.DqNehf.rst deleted file mode 100644 index fa07fa5226c0..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-28-15-12-53.gh-issue-103085.DqNehf.rst +++ /dev/null @@ -1 +0,0 @@ -Pure python :func:`locale.getencoding()` will not warn deprecation. diff --git a/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst b/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst deleted file mode 100644 index a9c19ce060e3..000000000000 --- a/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst +++ /dev/null @@ -1 +0,0 @@ -Improved test_locale_calendar_formatweekday of calendar. diff --git a/Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst b/Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst deleted file mode 100644 index 94d160dd4127..000000000000 --- a/Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst +++ /dev/null @@ -1,2 +0,0 @@ -Adjust the error handling strategy in -``test_zoneinfo.TzPathTest.python_tzpath_context``. Patch by Paul Ganssle. diff --git a/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst b/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst deleted file mode 100644 index 48277367fc87..000000000000 --- a/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst +++ /dev/null @@ -1 +0,0 @@ -Improve test coverage on :mod:`pdb`. diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-102809.2F1Byz.rst b/Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-102809.2F1Byz.rst deleted file mode 100644 index 5c2827698785..000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-102809.2F1Byz.rst +++ /dev/null @@ -1 +0,0 @@ -``Misc/gdbinit`` was removed. diff --git a/Misc/NEWS.d/next/Windows/2023-02-22-17-26-10.gh-issue-99726.76t957.rst b/Misc/NEWS.d/next/Windows/2023-02-22-17-26-10.gh-issue-99726.76t957.rst deleted file mode 100644 index e25786200178..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-02-22-17-26-10.gh-issue-99726.76t957.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improves correctness of stat results for Windows, and uses faster API when -available diff --git a/Misc/NEWS.d/next/Windows/2023-03-14-10-52-43.gh-issue-102690.sbXtqk.rst b/Misc/NEWS.d/next/Windows/2023-03-14-10-52-43.gh-issue-102690.sbXtqk.rst deleted file mode 100644 index 5669ebbb442c..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-03-14-10-52-43.gh-issue-102690.sbXtqk.rst +++ /dev/null @@ -1 +0,0 @@ -Update :mod:`webbrowser` to fall back to Microsoft Edge instead of Internet Explorer. diff --git a/README.rst b/README.rst index 6923b692f6c9..06c4f0a1fa39 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.12.0 alpha 6 +This is Python version 3.12.0 alpha 7 ===================================== .. image:: https://github.com/python/cpython/workflows/Tests/badge.svg From webhook-mailer at python.org Tue Apr 4 16:44:02 2023 From: webhook-mailer at python.org (ned-deily) Date: Tue, 04 Apr 2023 20:44:02 -0000 Subject: [Python-checkins] =?utf-8?q?=5B3=2E11=5D_gh-103207=3A_Add_instru?= =?utf-8?q?ctions_to_the_macOS_installer_welcome_display_on_how_to_workaro?= =?utf-8?q?und_the_macOS_13_Ventura_=E2=80=9CThe_installer_encountered_an_?= =?utf-8?q?error=E2=80=9D_failure=2E_GH-103252=29?= Message-ID: https://github.com/python/cpython/commit/6abd0486bbb30b9d2c99b00412d5641f9c778b88 commit: 6abd0486bbb30b9d2c99b00412d5641f9c778b88 branch: 3.11 author: Ned Deily committer: ned-deily date: 2023-04-04T16:43:54-04:00 summary: [3.11] gh-103207: Add instructions to the macOS installer welcome display on how to workaround the macOS 13 Ventura ?The installer encountered an error? failure. GH-103252) files: A Misc/NEWS.d/next/macOS/2023-04-04-13-37-28.gh-issue-103207.x0vvQp.rst M Mac/BuildScript/resources/Welcome.rtf diff --git a/Mac/BuildScript/resources/Welcome.rtf b/Mac/BuildScript/resources/Welcome.rtf index 4a0dac36320d..9adf4173ff16 100644 --- a/Mac/BuildScript/resources/Welcome.rtf +++ b/Mac/BuildScript/resources/Welcome.rtf @@ -1,9 +1,9 @@ -{\rtf1\ansi\ansicpg1252\cocoartf2639 +{\rtf1\ansi\ansicpg1252\cocoartf2708 \cocoascreenfonts1\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;\f2\fmodern\fcharset0 CourierNewPSMT; -} -{\colortbl;\red255\green255\blue255;} -{\*\expandedcolortbl;;} -\paperw11905\paperh16837\margl1440\margr1440\vieww12200\viewh10880\viewkind0 +\f3\fnil\fcharset0 HelveticaNeue;\f4\fnil\fcharset0 HelveticaNeue-Bold;} +{\colortbl;\red255\green255\blue255;\red24\green26\blue30;\red255\green255\blue255;} +{\*\expandedcolortbl;;\cssrgb\c12157\c13725\c15686;\cssrgb\c100000\c100000\c100000;} +\margl1440\margr1440\vieww12200\viewh10880\viewkind0 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\partightenfactor0 \f0\fs24 \cf0 This package will install @@ -12,8 +12,9 @@ \f1\b macOS $MACOSX_DEPLOYMENT_TARGET \f0\b0 .\ \ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\partightenfactor0 -\f1\b Python for macOS +\f1\b \cf0 Python for macOS \f0\b0 consists of the {\field{\*\fldinst{HYPERLINK "https://www.python.org"}}{\fldrslt Python}} programming language interpreter and its batteries-included standard library to allow easy access to macOS features. It also includes the Python integrated development environment, \f1\b IDLE \f0\b0 . You can also use the included @@ -23,4 +24,33 @@ At the end of this install, click on \f2 Install Certificates \f0 to install a set of current SSL root certificates.\ +\ + +\f1\b macOS 13 Ventura users +\f0\b0 : due to an issue with macOS +\f1\b Installer +\f0\b0 app, installation of some +\f3 \cf2 \cb3 \expnd0\expndtw0\kerning0 +third-party +\f0 \cf0 \cb1 \kerning1\expnd0\expndtw0 packages including this Python package may fail with a vague +\f4\b \cf2 \cb3 \expnd0\expndtw0\kerning0 +\'93The installer encountered an error\'94 +\f3\b0 \cf2 message if the +\f4\b \cf2 Installer +\f3\b0 \cf2 app does not have permission to access the folder containing the downloaded installer file, typically in the +\f4\b \cf2 Downloads +\f3\b0 \cf2 folder. Go to +\f4\b \cf2 System Settings +\f3\b0 \cf2 -> +\f4\b \cf2 Privacy & Security +\f3\b0 \cf2 -> +\f4\b \cf2 Files and Folders +\f3\b0 \cf2 , then click the mark in front of +\f4\b \cf2 Installer +\f3\b0 \cf2 to expand, and enable +\f4\b \cf2 Downloads Folder +\f0\b0 \cf0 \cb1 \kerning1\expnd0\expndtw0 by moving the toggle to the right +\f3 \cf2 \cb3 \expnd0\expndtw0\kerning0 +. See {\field{\*\fldinst{HYPERLINK "https://github.com/python/cpython/issues/103207"}}{\fldrslt https://github.com/python/cpython/issues/103207}} for up-to-date information on this issue. +\f0 \cf0 \cb1 \kerning1\expnd0\expndtw0 \ } \ No newline at end of file diff --git a/Misc/NEWS.d/next/macOS/2023-04-04-13-37-28.gh-issue-103207.x0vvQp.rst b/Misc/NEWS.d/next/macOS/2023-04-04-13-37-28.gh-issue-103207.x0vvQp.rst new file mode 100644 index 000000000000..3c176e3a6b53 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-04-04-13-37-28.gh-issue-103207.x0vvQp.rst @@ -0,0 +1,2 @@ +Add instructions to the macOS installer welcome display on how to workaround +the macOS 13 Ventura ?The installer encountered an error? failure. From webhook-mailer at python.org Tue Apr 4 17:06:08 2023 From: webhook-mailer at python.org (ned-deily) Date: Tue, 04 Apr 2023 21:06:08 -0000 Subject: [Python-checkins] =?utf-8?q?gh-103207=3A_Add_instructions_to_the?= =?utf-8?q?_macOS_installer_welcome_display_on_how_to_workaround__the_macO?= =?utf-8?q?S_13_Ventura_=E2=80=9CThe_installer_encountered_an_error?= =?utf-8?b?4oCdIGZhaWx1cmUuIChHSC0xMDMyNTEp?= Message-ID: https://github.com/python/cpython/commit/f184abbdc9ac3a5656de5f606faf505aa42ff391 commit: f184abbdc9ac3a5656de5f606faf505aa42ff391 branch: main author: Ned Deily committer: ned-deily date: 2023-04-04T17:06:00-04:00 summary: gh-103207: Add instructions to the macOS installer welcome display on how to workaround the macOS 13 Ventura ?The installer encountered an error? failure. (GH-103251) files: A Misc/NEWS.d/next/macOS/2023-04-04-13-37-28.gh-issue-103207.x0vvQp.rst M Mac/BuildScript/resources/Welcome.rtf diff --git a/Mac/BuildScript/resources/Welcome.rtf b/Mac/BuildScript/resources/Welcome.rtf index 7819241b618d..efdcb12f849b 100644 --- a/Mac/BuildScript/resources/Welcome.rtf +++ b/Mac/BuildScript/resources/Welcome.rtf @@ -1,9 +1,9 @@ -{\rtf1\ansi\ansicpg1252\cocoartf2639 +{\rtf1\ansi\ansicpg1252\cocoartf2708 \cocoascreenfonts1\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;\f2\fmodern\fcharset0 CourierNewPSMT; -} -{\colortbl;\red255\green255\blue255;} -{\*\expandedcolortbl;;} -\paperw11900\paperh16840\margl1440\margr1440\vieww12200\viewh10880\viewkind0 +\f3\fnil\fcharset0 HelveticaNeue;\f4\fnil\fcharset0 HelveticaNeue-Bold;} +{\colortbl;\red255\green255\blue255;\red24\green26\blue30;\red255\green255\blue255;} +{\*\expandedcolortbl;;\cssrgb\c12157\c13725\c15686;\cssrgb\c100000\c100000\c100000;} +\margl1440\margr1440\vieww12820\viewh10620\viewkind0 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\partightenfactor0 \f0\fs24 \cf0 This package will install @@ -25,6 +25,35 @@ At the end of this install, click on \f0 to install a set of current SSL root certificates.\ \ +\f1\b macOS 13 Ventura users +\f0\b0 : due to an issue with macOS +\f1\b Installer +\f0\b0 app, installation of some +\f3 \cf2 \cb3 \expnd0\expndtw0\kerning0 +third-party +\f0 \cf0 \cb1 \kerning1\expnd0\expndtw0 packages including this Python package may fail with a vague +\f4\b \cf2 \cb3 \expnd0\expndtw0\kerning0 +\'93The installer encountered an error\'94 +\f3\b0 message if the +\f4\b Installer +\f3\b0 app does not have permission to access the folder containing the downloaded installer file, typically in the +\f4\b Downloads +\f3\b0 folder. Go to +\f4\b System Settings +\f3\b0 -> +\f4\b Privacy & Security +\f3\b0 -> +\f4\b Files and Folders +\f3\b0 , then click the mark in front of +\f4\b Installer +\f3\b0 to expand, and enable +\f4\b Downloads Folder +\f0\b0 \cf0 \cb1 \kerning1\expnd0\expndtw0 by moving the toggle to the right +\f3 \cf2 \cb3 \expnd0\expndtw0\kerning0 +. See {\field{\*\fldinst{HYPERLINK "https://github.com/python/cpython/issues/103207"}}{\fldrslt https://github.com/python/cpython/issues/103207}} for up-to-date information on this issue. +\f0 \cf0 \cb1 \kerning1\expnd0\expndtw0 \ +\ + \f1\b NOTE: \f0\b0 This is an alpha test preview of Python 3.12.0, the next feature release of Python 3. It is not intended for production use.\ } \ No newline at end of file diff --git a/Misc/NEWS.d/next/macOS/2023-04-04-13-37-28.gh-issue-103207.x0vvQp.rst b/Misc/NEWS.d/next/macOS/2023-04-04-13-37-28.gh-issue-103207.x0vvQp.rst new file mode 100644 index 000000000000..3c176e3a6b53 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-04-04-13-37-28.gh-issue-103207.x0vvQp.rst @@ -0,0 +1,2 @@ +Add instructions to the macOS installer welcome display on how to workaround +the macOS 13 Ventura ?The installer encountered an error? failure. From webhook-mailer at python.org Tue Apr 4 18:24:20 2023 From: webhook-mailer at python.org (zooba) Date: Tue, 04 Apr 2023 22:24:20 -0000 Subject: [Python-checkins] GH-75586: Make shutil.which() on Windows more consistent with the OS (GH-103179) Message-ID: https://github.com/python/cpython/commit/935aa452359ac3f79febefcdb4387b962cf528af commit: 935aa452359ac3f79febefcdb4387b962cf528af branch: main author: Charles Machalow committer: zooba date: 2023-04-04T23:24:13+01:00 summary: GH-75586: Make shutil.which() on Windows more consistent with the OS (GH-103179) files: A Misc/NEWS.d/next/Library/2023-04-02-22-04-26.gh-issue-75586.526iJm.rst M Doc/library/shutil.rst M Doc/whatsnew/3.12.rst M Lib/shutil.py M Lib/test/test_shutil.py M Modules/_winapi.c M Modules/clinic/_winapi.c.h diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index acba66258fe8..373cc7d60720 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -433,23 +433,43 @@ Directory and files operations When no *path* is specified, the results of :func:`os.environ` are used, returning either the "PATH" value or a fallback of :attr:`os.defpath`. - On Windows, the current directory is always prepended to the *path* whether - or not you use the default or provide your own, which is the behavior the - command shell uses when finding executables. Additionally, when finding the - *cmd* in the *path*, the ``PATHEXT`` environment variable is checked. For - example, if you call ``shutil.which("python")``, :func:`which` will search - ``PATHEXT`` to know that it should look for ``python.exe`` within the *path* - directories. For example, on Windows:: + On Windows, the current directory is prepended to the *path* if *mode* does + not include ``os.X_OK``. When the *mode* does include ``os.X_OK``, the + Windows API ``NeedCurrentDirectoryForExePathW`` will be consulted to + determine if the current directory should be prepended to *path*. To avoid + consulting the current working directory for executables: set the environment + variable ``NoDefaultCurrentDirectoryInExePath``. + + Also on Windows, the ``PATHEXT`` variable is used to resolve commands + that may not already include an extension. For example, if you call + ``shutil.which("python")``, :func:`which` will search ``PATHEXT`` + to know that it should look for ``python.exe`` within the *path* + directories. For example, on Windows:: >>> shutil.which("python") 'C:\\Python33\\python.EXE' + This is also applied when *cmd* is a path that contains a directory + component:: + + >> shutil.which("C:\\Python33\\python") + 'C:\\Python33\\python.EXE' + .. versionadded:: 3.3 .. versionchanged:: 3.8 The :class:`bytes` type is now accepted. If *cmd* type is :class:`bytes`, the result type is also :class:`bytes`. + .. versionchanged:: 3.12 + On Windows, the current directory is no longer prepended to the search + path if *mode* includes ``os.X_OK`` and WinAPI + ``NeedCurrentDirectoryForExePathW(cmd)`` is false, else the current + directory is prepended even if it is already in the search path; + ``PATHEXT`` is used now even when *cmd* includes a directory component + or ends with an extension that is in ``PATHEXT``; and filenames that + have no extension can now be found. + .. exception:: Error This exception collects exceptions that are raised during a multi-file diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 88b99828f0be..cc2c0560a57c 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -343,6 +343,20 @@ shutil will be removed in Python 3.14. (Contributed by Irit Katriel in :gh:`102828`.) +* :func:`shutil.which` now consults the *PATHEXT* environment variable to + find matches within *PATH* on Windows even when the given *cmd* includes + a directory component. + (Contributed by Charles Machalow in :gh:`103179`.) + + :func:`shutil.which` will call ``NeedCurrentDirectoryForExePathW`` when + querying for executables on Windows to determine if the current working + directory should be prepended to the search path. + (Contributed by Charles Machalow in :gh:`103179`.) + + :func:`shutil.which` will return a path matching the *cmd* with a component + from ``PATHEXT`` prior to a direct match elsewhere in the search path on + Windows. + (Contributed by Charles Machalow in :gh:`103179`.) sqlite3 ------- diff --git a/Lib/shutil.py b/Lib/shutil.py index b0576407e02f..8b378645a5a3 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -40,6 +40,9 @@ elif _WINDOWS: import nt +if sys.platform == 'win32': + import _winapi + COPY_BUFSIZE = 1024 * 1024 if _WINDOWS else 64 * 1024 # This should never be removed, see rationale in: # https://bugs.python.org/issue43743#msg393429 @@ -1449,6 +1452,16 @@ def _access_check(fn, mode): and not os.path.isdir(fn)) +def _win_path_needs_curdir(cmd, mode): + """ + On Windows, we can use NeedCurrentDirectoryForExePath to figure out + if we should add the cwd to PATH when searching for executables if + the mode is executable. + """ + return (not (mode & os.X_OK)) or _winapi.NeedCurrentDirectoryForExePath( + os.fsdecode(cmd)) + + def which(cmd, mode=os.F_OK | os.X_OK, path=None): """Given a command, mode, and a PATH string, return the path which conforms to the given mode on the PATH, or None if there is no such @@ -1459,60 +1472,54 @@ def which(cmd, mode=os.F_OK | os.X_OK, path=None): path. """ - # If we're given a path with a directory part, look it up directly rather - # than referring to PATH directories. This includes checking relative to the - # current directory, e.g. ./script - if os.path.dirname(cmd): - if _access_check(cmd, mode): - return cmd - return None - use_bytes = isinstance(cmd, bytes) - if path is None: - path = os.environ.get("PATH", None) - if path is None: - try: - path = os.confstr("CS_PATH") - except (AttributeError, ValueError): - # os.confstr() or CS_PATH is not available - path = os.defpath - # bpo-35755: Don't use os.defpath if the PATH environment variable is - # set to an empty string - - # PATH='' doesn't match, whereas PATH=':' looks in the current directory - if not path: - return None - - if use_bytes: - path = os.fsencode(path) - path = path.split(os.fsencode(os.pathsep)) + # If we're given a path with a directory part, look it up directly rather + # than referring to PATH directories. This includes checking relative to + # the current directory, e.g. ./script + dirname, cmd = os.path.split(cmd) + if dirname: + path = [dirname] else: - path = os.fsdecode(path) - path = path.split(os.pathsep) + if path is None: + path = os.environ.get("PATH", None) + if path is None: + try: + path = os.confstr("CS_PATH") + except (AttributeError, ValueError): + # os.confstr() or CS_PATH is not available + path = os.defpath + # bpo-35755: Don't use os.defpath if the PATH environment variable + # is set to an empty string + + # PATH='' doesn't match, whereas PATH=':' looks in the current + # directory + if not path: + return None - if sys.platform == "win32": - # The current directory takes precedence on Windows. - curdir = os.curdir if use_bytes: - curdir = os.fsencode(curdir) - if curdir not in path: + path = os.fsencode(path) + path = path.split(os.fsencode(os.pathsep)) + else: + path = os.fsdecode(path) + path = path.split(os.pathsep) + + if sys.platform == "win32" and _win_path_needs_curdir(cmd, mode): + curdir = os.curdir + if use_bytes: + curdir = os.fsencode(curdir) path.insert(0, curdir) + if sys.platform == "win32": # PATHEXT is necessary to check on Windows. pathext_source = os.getenv("PATHEXT") or _WIN_DEFAULT_PATHEXT pathext = [ext for ext in pathext_source.split(os.pathsep) if ext] if use_bytes: pathext = [os.fsencode(ext) for ext in pathext] - # See if the given file matches any of the expected path extensions. - # This will allow us to short circuit when given "python.exe". - # If it does match, only test that one, otherwise we have to try - # others. - if any(cmd.lower().endswith(ext.lower()) for ext in pathext): - files = [cmd] - else: - files = [cmd + ext for ext in pathext] + + # Always try checking the originally given cmd, if it doesn't match, try pathext + files = [cmd] + [cmd + ext for ext in pathext] else: # On other platforms you don't have things like PATHEXT to tell you # what file suffixes are executable, so just pass on cmd as-is. diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 1c0589ced9ea..9eaf167a9fa3 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -2034,18 +2034,68 @@ def test_relative_cmd(self): rv = shutil.which(relpath, path=base_dir) self.assertIsNone(rv) - def test_cwd(self): + @unittest.skipUnless(sys.platform != "win32", + "test is for non win32") + def test_cwd_non_win32(self): # Issue #16957 base_dir = os.path.dirname(self.dir) with os_helper.change_cwd(path=self.dir): rv = shutil.which(self.file, path=base_dir) - if sys.platform == "win32": - # Windows: current directory implicitly on PATH + # non-win32: shouldn't match in the current directory. + self.assertIsNone(rv) + + @unittest.skipUnless(sys.platform == "win32", + "test is for win32") + def test_cwd_win32(self): + base_dir = os.path.dirname(self.dir) + with os_helper.change_cwd(path=self.dir): + with unittest.mock.patch('shutil._win_path_needs_curdir', return_value=True): + rv = shutil.which(self.file, path=base_dir) + # Current directory implicitly on PATH self.assertEqual(rv, os.path.join(self.curdir, self.file)) - else: - # Other platforms: shouldn't match in the current directory. + with unittest.mock.patch('shutil._win_path_needs_curdir', return_value=False): + rv = shutil.which(self.file, path=base_dir) + # Current directory not on PATH self.assertIsNone(rv) + @unittest.skipUnless(sys.platform == "win32", + "test is for win32") + def test_cwd_win32_added_before_all_other_path(self): + base_dir = pathlib.Path(os.fsdecode(self.dir)) + + elsewhere_in_path_dir = base_dir / 'dir1' + elsewhere_in_path_dir.mkdir() + match_elsewhere_in_path = elsewhere_in_path_dir / 'hello.exe' + match_elsewhere_in_path.touch() + + exe_in_cwd = base_dir / 'hello.exe' + exe_in_cwd.touch() + + with os_helper.change_cwd(path=base_dir): + with unittest.mock.patch('shutil._win_path_needs_curdir', return_value=True): + rv = shutil.which('hello.exe', path=elsewhere_in_path_dir) + + self.assertEqual(os.path.abspath(rv), os.path.abspath(exe_in_cwd)) + + @unittest.skipUnless(sys.platform == "win32", + "test is for win32") + def test_pathext_match_before_path_full_match(self): + base_dir = pathlib.Path(os.fsdecode(self.dir)) + dir1 = base_dir / 'dir1' + dir2 = base_dir / 'dir2' + dir1.mkdir() + dir2.mkdir() + + pathext_match = dir1 / 'hello.com.exe' + path_match = dir2 / 'hello.com' + pathext_match.touch() + path_match.touch() + + test_path = os.pathsep.join([str(dir1), str(dir2)]) + assert os.path.basename(shutil.which( + 'hello.com', path=test_path, mode = os.F_OK + )).lower() == 'hello.com.exe' + @os_helper.skip_if_dac_override def test_non_matching_mode(self): # Set the file read-only and ask for writeable files. @@ -2179,6 +2229,32 @@ def test_pathext_with_empty_str(self): rv = shutil.which(program, path=self.temp_dir) self.assertEqual(rv, temp_filexyz.name) + # See GH-75586 + @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') + def test_pathext_applied_on_files_in_path(self): + with os_helper.EnvironmentVarGuard() as env: + env["PATH"] = self.temp_dir + env["PATHEXT"] = ".test" + + test_path = pathlib.Path(self.temp_dir) / "test_program.test" + test_path.touch(mode=0o755) + + self.assertEqual(shutil.which("test_program"), str(test_path)) + + # See GH-75586 + @unittest.skipUnless(sys.platform == "win32", 'test specific to Windows') + def test_win_path_needs_curdir(self): + with unittest.mock.patch('_winapi.NeedCurrentDirectoryForExePath', return_value=True) as need_curdir_mock: + self.assertTrue(shutil._win_path_needs_curdir('dontcare', os.X_OK)) + need_curdir_mock.assert_called_once_with('dontcare') + need_curdir_mock.reset_mock() + self.assertTrue(shutil._win_path_needs_curdir('dontcare', 0)) + need_curdir_mock.assert_not_called() + + with unittest.mock.patch('_winapi.NeedCurrentDirectoryForExePath', return_value=False) as need_curdir_mock: + self.assertFalse(shutil._win_path_needs_curdir('dontcare', os.X_OK)) + need_curdir_mock.assert_called_once_with('dontcare') + class TestWhichBytes(TestWhich): def setUp(self): diff --git a/Misc/NEWS.d/next/Library/2023-04-02-22-04-26.gh-issue-75586.526iJm.rst b/Misc/NEWS.d/next/Library/2023-04-02-22-04-26.gh-issue-75586.526iJm.rst new file mode 100644 index 000000000000..8ec568ec4e47 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-02-22-04-26.gh-issue-75586.526iJm.rst @@ -0,0 +1 @@ +Fix various Windows-specific issues with ``shutil.which``. diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 83cde7501176..fa380b8b7984 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -2054,6 +2054,26 @@ _winapi__mimetypes_read_windows_registry_impl(PyObject *module, #undef CB_TYPE } +/*[clinic input] +_winapi.NeedCurrentDirectoryForExePath -> bool + + exe_name: LPCWSTR + / +[clinic start generated code]*/ + +static int +_winapi_NeedCurrentDirectoryForExePath_impl(PyObject *module, + LPCWSTR exe_name) +/*[clinic end generated code: output=a65ec879502b58fc input=972aac88a1ec2f00]*/ +{ + BOOL result; + + Py_BEGIN_ALLOW_THREADS + result = NeedCurrentDirectoryForExePathW(exe_name); + Py_END_ALLOW_THREADS + + return result; +} static PyMethodDef winapi_functions[] = { _WINAPI_CLOSEHANDLE_METHODDEF @@ -2089,6 +2109,7 @@ static PyMethodDef winapi_functions[] = { _WINAPI_GETACP_METHODDEF _WINAPI_GETFILETYPE_METHODDEF _WINAPI__MIMETYPES_READ_WINDOWS_REGISTRY_METHODDEF + _WINAPI_NEEDCURRENTDIRECTORYFOREXEPATH_METHODDEF {NULL, NULL} }; diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index 891b3f851d12..7bc63e612be3 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -1371,4 +1371,44 @@ _winapi__mimetypes_read_windows_registry(PyObject *module, PyObject *const *args exit: return return_value; } -/*[clinic end generated code: output=edb1a9d1bbfd6394 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(_winapi_NeedCurrentDirectoryForExePath__doc__, +"NeedCurrentDirectoryForExePath($module, exe_name, /)\n" +"--\n" +"\n"); + +#define _WINAPI_NEEDCURRENTDIRECTORYFOREXEPATH_METHODDEF \ + {"NeedCurrentDirectoryForExePath", (PyCFunction)_winapi_NeedCurrentDirectoryForExePath, METH_O, _winapi_NeedCurrentDirectoryForExePath__doc__}, + +static int +_winapi_NeedCurrentDirectoryForExePath_impl(PyObject *module, + LPCWSTR exe_name); + +static PyObject * +_winapi_NeedCurrentDirectoryForExePath(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + LPCWSTR exe_name = NULL; + int _return_value; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("NeedCurrentDirectoryForExePath", "argument", "str", arg); + goto exit; + } + exe_name = PyUnicode_AsWideCharString(arg, NULL); + if (exe_name == NULL) { + goto exit; + } + _return_value = _winapi_NeedCurrentDirectoryForExePath_impl(module, exe_name); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + /* Cleanup for exe_name */ + PyMem_Free((void *)exe_name); + + return return_value; +} +/*[clinic end generated code: output=96ea65ece7912d0a input=a9049054013a1b77]*/ From webhook-mailer at python.org Tue Apr 4 18:46:54 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Tue, 04 Apr 2023 22:46:54 -0000 Subject: [Python-checkins] Improve some grammar in the socket docs (#103254) Message-ID: https://github.com/python/cpython/commit/bceb9e00ad2998e5193ad5b477e92a114dd31024 commit: bceb9e00ad2998e5193ad5b477e92a114dd31024 branch: main author: Tim Burke committer: AlexWaygood date: 2023-04-04T23:46:46+01:00 summary: Improve some grammar in the socket docs (#103254) files: M Doc/library/socket.rst diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index aec79da57f05..c8ca555700a3 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -1775,7 +1775,7 @@ to sockets. much data, if any, was successfully sent. .. versionchanged:: 3.5 - The socket timeout is no more reset each time data is sent successfully. + The socket timeout is no longer reset each time data is sent successfully. The socket timeout is now the maximum total duration to send all data. .. versionchanged:: 3.5 @@ -1998,8 +1998,8 @@ can be changed by calling :func:`setdefaulttimeout`. * In *non-blocking mode*, operations fail (with an error that is unfortunately system-dependent) if they cannot be completed immediately: functions from the - :mod:`select` can be used to know when and whether a socket is available for - reading or writing. + :mod:`select` module can be used to know when and whether a socket is available + for reading or writing. * In *timeout mode*, operations fail if they cannot be completed within the timeout specified for the socket (they raise a :exc:`timeout` exception) @@ -2188,7 +2188,7 @@ manager protocol instead, open a socket with:: socket.socket(socket.AF_CAN, socket.SOCK_DGRAM, socket.CAN_BCM) After binding (:const:`CAN_RAW`) or connecting (:const:`CAN_BCM`) the socket, you -can use the :meth:`socket.send`, and the :meth:`socket.recv` operations (and +can use the :meth:`socket.send` and :meth:`socket.recv` operations (and their counterparts) on the socket object as usual. This last example might require special privileges:: From webhook-mailer at python.org Tue Apr 4 18:54:44 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 04 Apr 2023 22:54:44 -0000 Subject: [Python-checkins] Improve some grammar in the socket docs (GH-103254) Message-ID: https://github.com/python/cpython/commit/6258c3cd53214af07c69df0e8544f70c981f29f1 commit: 6258c3cd53214af07c69df0e8544f70c981f29f1 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-04T15:54:37-07:00 summary: Improve some grammar in the socket docs (GH-103254) (cherry picked from commit bceb9e00ad2998e5193ad5b477e92a114dd31024) Co-authored-by: Tim Burke files: M Doc/library/socket.rst diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index bb689c4df8de..d1b5a1ceb737 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -1688,7 +1688,7 @@ to sockets. much data, if any, was successfully sent. .. versionchanged:: 3.5 - The socket timeout is no more reset each time data is sent successfully. + The socket timeout is no longer reset each time data is sent successfully. The socket timeout is now the maximum total duration to send all data. .. versionchanged:: 3.5 @@ -1911,8 +1911,8 @@ can be changed by calling :func:`setdefaulttimeout`. * In *non-blocking mode*, operations fail (with an error that is unfortunately system-dependent) if they cannot be completed immediately: functions from the - :mod:`select` can be used to know when and whether a socket is available for - reading or writing. + :mod:`select` module can be used to know when and whether a socket is available + for reading or writing. * In *timeout mode*, operations fail if they cannot be completed within the timeout specified for the socket (they raise a :exc:`timeout` exception) @@ -2101,7 +2101,7 @@ manager protocol instead, open a socket with:: socket.socket(socket.AF_CAN, socket.SOCK_DGRAM, socket.CAN_BCM) After binding (:const:`CAN_RAW`) or connecting (:const:`CAN_BCM`) the socket, you -can use the :meth:`socket.send`, and the :meth:`socket.recv` operations (and +can use the :meth:`socket.send` and :meth:`socket.recv` operations (and their counterparts) on the socket object as usual. This last example might require special privileges:: From webhook-mailer at python.org Tue Apr 4 18:55:19 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 04 Apr 2023 22:55:19 -0000 Subject: [Python-checkins] Improve some grammar in the socket docs (GH-103254) Message-ID: https://github.com/python/cpython/commit/d76a5c6f7b1caf55c2162fd66bcdb9d8dd890005 commit: d76a5c6f7b1caf55c2162fd66bcdb9d8dd890005 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-04T15:55:11-07:00 summary: Improve some grammar in the socket docs (GH-103254) (cherry picked from commit bceb9e00ad2998e5193ad5b477e92a114dd31024) Co-authored-by: Tim Burke files: M Doc/library/socket.rst diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 6fb6d5fd8b1b..cd0d2ce0f112 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -1596,7 +1596,7 @@ to sockets. much data, if any, was successfully sent. .. versionchanged:: 3.5 - The socket timeout is no more reset each time data is sent successfully. + The socket timeout is no longer reset each time data is sent successfully. The socket timeout is now the maximum total duration to send all data. .. versionchanged:: 3.5 @@ -1814,8 +1814,8 @@ can be changed by calling :func:`setdefaulttimeout`. * In *non-blocking mode*, operations fail (with an error that is unfortunately system-dependent) if they cannot be completed immediately: functions from the - :mod:`select` can be used to know when and whether a socket is available for - reading or writing. + :mod:`select` module can be used to know when and whether a socket is available + for reading or writing. * In *timeout mode*, operations fail if they cannot be completed within the timeout specified for the socket (they raise a :exc:`timeout` exception) @@ -2004,7 +2004,7 @@ manager protocol instead, open a socket with:: socket.socket(socket.AF_CAN, socket.SOCK_DGRAM, socket.CAN_BCM) After binding (:const:`CAN_RAW`) or connecting (:const:`CAN_BCM`) the socket, you -can use the :meth:`socket.send`, and the :meth:`socket.recv` operations (and +can use the :meth:`socket.send` and :meth:`socket.recv` operations (and their counterparts) on the socket object as usual. This last example might require special privileges:: From webhook-mailer at python.org Tue Apr 4 19:03:47 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Tue, 04 Apr 2023 23:03:47 -0000 Subject: [Python-checkins] gh-102660: Fix is_core_module() (gh-103257) Message-ID: https://github.com/python/cpython/commit/f513d5c80672c76acbdaf7d5b601f4bbe9fae56a commit: f513d5c80672c76acbdaf7d5b601f4bbe9fae56a branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-04-04T17:03:40-06:00 summary: gh-102660: Fix is_core_module() (gh-103257) In gh-102744 we added is_core_module() (in Python/import.c), which relies on get_core_module_dict() (also added in that PR). The problem is that_PyImport_FixupBuiltin(), which ultimately calls is_core_module(), is called on the builtins module before interp->builtins_copyis set. Consequently, the builtins module isn't considered a "core" module while it is getting "fixed up" and its module def m_copy erroneously gets set. Under isolated interpreters this causes problems since sys and builtins are allowed even though they are still single-phase init modules. (This was discovered while working on gh-101660.) The solution is to stop relying on get_core_module_dict() in is_core_module(). files: M Python/import.c diff --git a/Python/import.c b/Python/import.c index 24249ae4a6ad..1db5b9333bbb 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1110,7 +1110,17 @@ get_core_module_dict(PyInterpreterState *interp, static inline int is_core_module(PyInterpreterState *interp, PyObject *name, PyObject *filename) { - return get_core_module_dict(interp, name, filename) != NULL; + /* This might be called before the core dict copies are in place, + so we can't rely on get_core_module_dict() here. */ + if (filename == name) { + if (PyUnicode_CompareWithASCIIString(name, "sys") == 0) { + return 1; + } + if (PyUnicode_CompareWithASCIIString(name, "builtins") == 0) { + return 1; + } + } + return 0; } static int @@ -1136,6 +1146,8 @@ fix_up_extension(PyObject *mod, PyObject *name, PyObject *filename) // when the extension module doesn't support sub-interpreters. if (def->m_size == -1) { if (!is_core_module(tstate->interp, name, filename)) { + assert(PyUnicode_CompareWithASCIIString(name, "sys") != 0); + assert(PyUnicode_CompareWithASCIIString(name, "builtins") != 0); if (def->m_base.m_copy) { /* Somebody already imported the module, likely under a different name. From webhook-mailer at python.org Tue Apr 4 20:11:00 2023 From: webhook-mailer at python.org (corona10) Date: Wed, 05 Apr 2023 00:11:00 -0000 Subject: [Python-checkins] gh-101525: Disable peephole optimization process of BOLT (gh-103187) Message-ID: https://github.com/python/cpython/commit/a62ff970750267441a7175b1bd6d6b2ec59d9a2c commit: a62ff970750267441a7175b1bd6d6b2ec59d9a2c branch: main author: Dong-hee Na committer: corona10 date: 2023-04-05T09:10:45+09:00 summary: gh-101525: Disable peephole optimization process of BOLT (gh-103187) Co-authored-by: Dong-hee Na files: M Doc/whatsnew/3.12.rst M Makefile.pre.in diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index cc2c0560a57c..23524ec5d7d4 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -465,7 +465,7 @@ Optimizations * Added experimental support for using the BOLT binary optimizer in the build process, which improves performance by 1-5%. - (Contributed by Kevin Modzelewski in :gh:`90536`.) + (Contributed by Kevin Modzelewski in :gh:`90536` and tuned by Dong-hee Na in :gh:`101525`) * Speed up the regular expression substitution (functions :func:`re.sub` and :func:`re.subn` and corresponding :class:`!re.Pattern` methods) for diff --git a/Makefile.pre.in b/Makefile.pre.in index b97daaf6f445..9fdbd8db19bb 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -670,7 +670,7 @@ bolt-opt: @PREBOLT_RULE@ @LLVM_BOLT@ ./$(BUILDPYTHON) -instrument -instrumentation-file-append-pid -instrumentation-file=$(abspath $(BUILDPYTHON).bolt) -o $(BUILDPYTHON).bolt_inst ./$(BUILDPYTHON).bolt_inst $(PROFILE_TASK) || true @MERGE_FDATA@ $(BUILDPYTHON).*.fdata > $(BUILDPYTHON).fdata - @LLVM_BOLT@ ./$(BUILDPYTHON) -o $(BUILDPYTHON).bolt -data=$(BUILDPYTHON).fdata -update-debug-sections -reorder-blocks=ext-tsp -reorder-functions=hfsort+ -split-functions -icf=1 -inline-all -split-eh -reorder-functions-use-hot-size -peepholes=all -jump-tables=aggressive -inline-ap -indirect-call-promotion=all -dyno-stats -use-gnu-stack -frame-opt=hot + @LLVM_BOLT@ ./$(BUILDPYTHON) -o $(BUILDPYTHON).bolt -data=$(BUILDPYTHON).fdata -update-debug-sections -reorder-blocks=ext-tsp -reorder-functions=hfsort+ -split-functions -icf=1 -inline-all -split-eh -reorder-functions-use-hot-size -peepholes=none -jump-tables=aggressive -inline-ap -indirect-call-promotion=all -dyno-stats -use-gnu-stack -frame-opt=hot rm -f *.fdata rm -f $(BUILDPYTHON).bolt_inst mv $(BUILDPYTHON).bolt $(BUILDPYTHON) From webhook-mailer at python.org Wed Apr 5 00:55:41 2023 From: webhook-mailer at python.org (orsenthil) Date: Wed, 05 Apr 2023 04:55:41 -0000 Subject: [Python-checkins] gh-66897: Upgrade HTTP CONNECT to protocol HTTP/1.1 (#8305) Message-ID: https://github.com/python/cpython/commit/1a8f862e329c3872a11d4ef8eb85cf353ca2f4d5 commit: 1a8f862e329c3872a11d4ef8eb85cf353ca2f4d5 branch: main author: Michael Handler committer: orsenthil date: 2023-04-04T21:55:24-07:00 summary: gh-66897: Upgrade HTTP CONNECT to protocol HTTP/1.1 (#8305) * bpo-22708: Upgrade HTTP CONNECT to protocol HTTP/1.1 (GH-NNNN) Use protocol HTTP/1.1 when sending HTTP CONNECT tunnelling requests; generate Host: headers if one is not already provided (required by HTTP/1.1), convert IDN domains to punycode in HTTP CONNECT requests. * Refactor tests to pass under -bb (fix ByteWarnings); missed some lines >80. * Use consistent 'tunnelling' spelling in Lib/http/client.py * Lib/test/test_httplib: Remove remnant of obsoleted test. * Use dict.copy() not copy.copy() * fix version changed * Update Lib/http/client.py Co-authored-by: bgehman * Switch to for/else: syntax, as suggested * Don't use for: else: * Sure, fine, w/e * Oops * 1nm to the left --------- Co-authored-by: ?ric Co-authored-by: bgehman Co-authored-by: Oleg Iarygin files: A Misc/NEWS.d/next/Library/2018-07-16-14-10-29.bpo-22708.592iRR.rst M Doc/library/http.client.rst M Lib/http/client.py M Lib/test/test_httplib.py M Misc/ACKS diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index ad3416135e30..38821b32c91c 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -353,6 +353,13 @@ HTTPConnection Objects The *headers* argument should be a mapping of extra HTTP headers to send with the CONNECT request. + As HTTP/1.1 is used for HTTP CONNECT tunnelling request, `as per the RFC + `_, a HTTP ``Host:`` + header must be provided, matching the authority-form of the request target + provided as the destination for the CONNECT request. If a HTTP ``Host:`` + header is not provided via the headers argument, one is generated and + transmitted automatically. + For example, to tunnel through a HTTPS proxy server running locally on port 8080, we would pass the address of the proxy to the :class:`HTTPSConnection` constructor, and the address of the host that we eventually want to reach to @@ -365,6 +372,11 @@ HTTPConnection Objects .. versionadded:: 3.2 + .. versionchanged:: 3.12 + HTTP CONNECT tunnelling requests use protocol HTTP/1.1, upgraded from + protocol HTTP/1.0. ``Host:`` HTTP headers are mandatory for HTTP/1.1, so + one will be automatically generated and transmitted if not provided in + the headers argument. .. method:: HTTPConnection.connect() diff --git a/Lib/http/client.py b/Lib/http/client.py index bd55e7d239af..0f5cd35247ae 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -870,9 +870,9 @@ def __init__(self, host, port=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, def set_tunnel(self, host, port=None, headers=None): """Set up host and port for HTTP CONNECT tunnelling. - In a connection that uses HTTP CONNECT tunneling, the host passed to the - constructor is used as a proxy server that relays all communication to - the endpoint passed to `set_tunnel`. This done by sending an HTTP + In a connection that uses HTTP CONNECT tunnelling, the host passed to + the constructor is used as a proxy server that relays all communication + to the endpoint passed to `set_tunnel`. This done by sending an HTTP CONNECT request to the proxy server when the connection is established. This method must be called before the HTTP connection has been @@ -880,6 +880,13 @@ def set_tunnel(self, host, port=None, headers=None): The headers argument should be a mapping of extra HTTP headers to send with the CONNECT request. + + As HTTP/1.1 is used for HTTP CONNECT tunnelling request, as per the RFC + (https://tools.ietf.org/html/rfc7231#section-4.3.6), a HTTP Host: + header must be provided, matching the authority-form of the request + target provided as the destination for the CONNECT request. If a + HTTP Host: header is not provided via the headers argument, one + is generated and transmitted automatically. """ if self.sock: @@ -887,10 +894,15 @@ def set_tunnel(self, host, port=None, headers=None): self._tunnel_host, self._tunnel_port = self._get_hostport(host, port) if headers: - self._tunnel_headers = headers + self._tunnel_headers = headers.copy() else: self._tunnel_headers.clear() + if not any(header.lower() == "host" for header in self._tunnel_headers): + encoded_host = self._tunnel_host.encode("idna").decode("ascii") + self._tunnel_headers["Host"] = "%s:%d" % ( + encoded_host, self._tunnel_port) + def _get_hostport(self, host, port): if port is None: i = host.rfind(':') @@ -915,8 +927,9 @@ def set_debuglevel(self, level): self.debuglevel = level def _tunnel(self): - connect = b"CONNECT %s:%d HTTP/1.0\r\n" % ( - self._tunnel_host.encode("ascii"), self._tunnel_port) + connect = b"CONNECT %s:%d %s\r\n" % ( + self._tunnel_host.encode("idna"), self._tunnel_port, + self._http_vsn_str.encode("ascii")) headers = [connect] for header, value in self._tunnel_headers.items(): headers.append(f"{header}: {value}\r\n".encode("latin-1")) diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index 9ff6afcbadec..b4f4e2b14351 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -2187,11 +2187,12 @@ def test_getting_header_defaultint(self): class TunnelTests(TestCase): def setUp(self): response_text = ( - 'HTTP/1.0 200 OK\r\n\r\n' # Reply to CONNECT + 'HTTP/1.1 200 OK\r\n\r\n' # Reply to CONNECT 'HTTP/1.1 200 OK\r\n' # Reply to HEAD 'Content-Length: 42\r\n\r\n' ) self.host = 'proxy.com' + self.port = client.HTTP_PORT self.conn = client.HTTPConnection(self.host) self.conn._create_connection = self._create_connection(response_text) @@ -2203,15 +2204,45 @@ def create_connection(address, timeout=None, source_address=None): return FakeSocket(response_text, host=address[0], port=address[1]) return create_connection - def test_set_tunnel_host_port_headers(self): + def test_set_tunnel_host_port_headers_add_host_missing(self): tunnel_host = 'destination.com' tunnel_port = 8888 tunnel_headers = {'User-Agent': 'Mozilla/5.0 (compatible, MSIE 11)'} + tunnel_headers_after = tunnel_headers.copy() + tunnel_headers_after['Host'] = '%s:%d' % (tunnel_host, tunnel_port) self.conn.set_tunnel(tunnel_host, port=tunnel_port, headers=tunnel_headers) self.conn.request('HEAD', '/', '') self.assertEqual(self.conn.sock.host, self.host) - self.assertEqual(self.conn.sock.port, client.HTTP_PORT) + self.assertEqual(self.conn.sock.port, self.port) + self.assertEqual(self.conn._tunnel_host, tunnel_host) + self.assertEqual(self.conn._tunnel_port, tunnel_port) + self.assertEqual(self.conn._tunnel_headers, tunnel_headers_after) + + def test_set_tunnel_host_port_headers_set_host_identical(self): + tunnel_host = 'destination.com' + tunnel_port = 8888 + tunnel_headers = {'User-Agent': 'Mozilla/5.0 (compatible, MSIE 11)', + 'Host': '%s:%d' % (tunnel_host, tunnel_port)} + self.conn.set_tunnel(tunnel_host, port=tunnel_port, + headers=tunnel_headers) + self.conn.request('HEAD', '/', '') + self.assertEqual(self.conn.sock.host, self.host) + self.assertEqual(self.conn.sock.port, self.port) + self.assertEqual(self.conn._tunnel_host, tunnel_host) + self.assertEqual(self.conn._tunnel_port, tunnel_port) + self.assertEqual(self.conn._tunnel_headers, tunnel_headers) + + def test_set_tunnel_host_port_headers_set_host_different(self): + tunnel_host = 'destination.com' + tunnel_port = 8888 + tunnel_headers = {'User-Agent': 'Mozilla/5.0 (compatible, MSIE 11)', + 'Host': '%s:%d' % ('example.com', 4200)} + self.conn.set_tunnel(tunnel_host, port=tunnel_port, + headers=tunnel_headers) + self.conn.request('HEAD', '/', '') + self.assertEqual(self.conn.sock.host, self.host) + self.assertEqual(self.conn.sock.port, self.port) self.assertEqual(self.conn._tunnel_host, tunnel_host) self.assertEqual(self.conn._tunnel_port, tunnel_port) self.assertEqual(self.conn._tunnel_headers, tunnel_headers) @@ -2223,17 +2254,96 @@ def test_disallow_set_tunnel_after_connect(self): 'destination.com') def test_connect_with_tunnel(self): - self.conn.set_tunnel('destination.com') + d = { + b'host': b'destination.com', + b'port': client.HTTP_PORT, + } + self.conn.set_tunnel(d[b'host'].decode('ascii')) + self.conn.request('HEAD', '/', '') + self.assertEqual(self.conn.sock.host, self.host) + self.assertEqual(self.conn.sock.port, self.port) + self.assertIn(b'CONNECT %(host)s:%(port)d HTTP/1.1\r\n' + b'Host: %(host)s:%(port)d\r\n\r\n' % d, + self.conn.sock.data) + self.assertIn(b'HEAD / HTTP/1.1\r\nHost: %(host)s\r\n' % d, + self.conn.sock.data) + + def test_connect_with_tunnel_with_default_port(self): + d = { + b'host': b'destination.com', + b'port': client.HTTP_PORT, + } + self.conn.set_tunnel(d[b'host'].decode('ascii'), port=d[b'port']) + self.conn.request('HEAD', '/', '') + self.assertEqual(self.conn.sock.host, self.host) + self.assertEqual(self.conn.sock.port, self.port) + self.assertIn(b'CONNECT %(host)s:%(port)d HTTP/1.1\r\n' + b'Host: %(host)s:%(port)d\r\n\r\n' % d, + self.conn.sock.data) + self.assertIn(b'HEAD / HTTP/1.1\r\nHost: %(host)s\r\n' % d, + self.conn.sock.data) + + def test_connect_with_tunnel_with_nonstandard_port(self): + d = { + b'host': b'destination.com', + b'port': 8888, + } + self.conn.set_tunnel(d[b'host'].decode('ascii'), port=d[b'port']) + self.conn.request('HEAD', '/', '') + self.assertEqual(self.conn.sock.host, self.host) + self.assertEqual(self.conn.sock.port, self.port) + self.assertIn(b'CONNECT %(host)s:%(port)d HTTP/1.1\r\n' + b'Host: %(host)s:%(port)d\r\n\r\n' % d, + self.conn.sock.data) + self.assertIn(b'HEAD / HTTP/1.1\r\nHost: %(host)s:%(port)d\r\n' % d, + self.conn.sock.data) + + # This request is not RFC-valid, but it's been possible with the library + # for years, so don't break it unexpectedly... This also tests + # case-insensitivity when injecting Host: headers if they're missing. + def test_connect_with_tunnel_with_different_host_header(self): + d = { + b'host': b'destination.com', + b'tunnel_host_header': b'example.com:9876', + b'port': client.HTTP_PORT, + } + self.conn.set_tunnel( + d[b'host'].decode('ascii'), + headers={'HOST': d[b'tunnel_host_header'].decode('ascii')}) + self.conn.request('HEAD', '/', '') + self.assertEqual(self.conn.sock.host, self.host) + self.assertEqual(self.conn.sock.port, self.port) + self.assertIn(b'CONNECT %(host)s:%(port)d HTTP/1.1\r\n' + b'HOST: %(tunnel_host_header)s\r\n\r\n' % d, + self.conn.sock.data) + self.assertIn(b'HEAD / HTTP/1.1\r\nHost: %(host)s\r\n' % d, + self.conn.sock.data) + + def test_connect_with_tunnel_different_host(self): + d = { + b'host': b'destination.com', + b'port': client.HTTP_PORT, + } + self.conn.set_tunnel(d[b'host'].decode('ascii')) + self.conn.request('HEAD', '/', '') + self.assertEqual(self.conn.sock.host, self.host) + self.assertEqual(self.conn.sock.port, self.port) + self.assertIn(b'CONNECT %(host)s:%(port)d HTTP/1.1\r\n' + b'Host: %(host)s:%(port)d\r\n\r\n' % d, + self.conn.sock.data) + self.assertIn(b'HEAD / HTTP/1.1\r\nHost: %(host)s\r\n' % d, + self.conn.sock.data) + + def test_connect_with_tunnel_idna(self): + dest = '\u03b4\u03c0\u03b8.gr' + dest_port = b'%s:%d' % (dest.encode('idna'), client.HTTP_PORT) + expected = b'CONNECT %s HTTP/1.1\r\nHost: %s\r\n\r\n' % ( + dest_port, dest_port) + self.conn.set_tunnel(dest) self.conn.request('HEAD', '/', '') self.assertEqual(self.conn.sock.host, self.host) self.assertEqual(self.conn.sock.port, client.HTTP_PORT) - self.assertIn(b'CONNECT destination.com', self.conn.sock.data) - # issue22095 - self.assertNotIn(b'Host: destination.com:None', self.conn.sock.data) - self.assertIn(b'Host: destination.com', self.conn.sock.data) - - # This test should be removed when CONNECT gets the HTTP/1.1 blessing - self.assertNotIn(b'Host: proxy.com', self.conn.sock.data) + self.assertIn(expected, self.conn.sock.data) def test_tunnel_connect_single_send_connection_setup(self): """Regresstion test for https://bugs.python.org/issue43332.""" @@ -2253,12 +2363,19 @@ def test_tunnel_connect_single_send_connection_setup(self): msg=f'unexpected proxy data sent {proxy_setup_data_sent!r}') def test_connect_put_request(self): - self.conn.set_tunnel('destination.com') + d = { + b'host': b'destination.com', + b'port': client.HTTP_PORT, + } + self.conn.set_tunnel(d[b'host'].decode('ascii')) self.conn.request('PUT', '/', '') self.assertEqual(self.conn.sock.host, self.host) - self.assertEqual(self.conn.sock.port, client.HTTP_PORT) - self.assertIn(b'CONNECT destination.com', self.conn.sock.data) - self.assertIn(b'Host: destination.com', self.conn.sock.data) + self.assertEqual(self.conn.sock.port, self.port) + self.assertIn(b'CONNECT %(host)s:%(port)d HTTP/1.1\r\n' + b'Host: %(host)s:%(port)d\r\n\r\n' % d, + self.conn.sock.data) + self.assertIn(b'PUT / HTTP/1.1\r\nHost: %(host)s\r\n' % d, + self.conn.sock.data) def test_tunnel_debuglog(self): expected_header = 'X-Dummy: 1' diff --git a/Misc/ACKS b/Misc/ACKS index 8cf5166a2bb1..929e06a87cb7 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -693,6 +693,7 @@ Anders Hammarquist Mark Hammond Harald Hanche-Olsen Manus Hand +Michael Handler Andreas Hangauer Milton L. Hankins Carl Bordum Hansen diff --git a/Misc/NEWS.d/next/Library/2018-07-16-14-10-29.bpo-22708.592iRR.rst b/Misc/NEWS.d/next/Library/2018-07-16-14-10-29.bpo-22708.592iRR.rst new file mode 100644 index 000000000000..00bcf38bbcdf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-07-16-14-10-29.bpo-22708.592iRR.rst @@ -0,0 +1,3 @@ +http.client CONNECT method tunnel improvements: Use HTTP 1.1 protocol; send +a matching Host: header with CONNECT, if one is not provided; convert IDN +domain names to Punycode. Patch by Michael Handler. From webhook-mailer at python.org Wed Apr 5 03:23:06 2023 From: webhook-mailer at python.org (encukou) Date: Wed, 05 Apr 2023 07:23:06 -0000 Subject: [Python-checkins] gh-103167: Fix `-Wstrict-prototypes` warnings by using `(void)` for functions with no args (GH-103168) Message-ID: https://github.com/python/cpython/commit/119f67de08f1fddc2a3f7b7caac7454cb57ef800 commit: 119f67de08f1fddc2a3f7b7caac7454cb57ef800 branch: main author: Nikita Sobolev committer: encukou date: 2023-04-05T09:22:33+02:00 summary: gh-103167: Fix `-Wstrict-prototypes` warnings by using `(void)` for functions with no args (GH-103168) files: M Modules/_tkinter.c M Modules/posixmodule.c M PC/launcher.c M PC/launcher2.c M Python/ceval_gil.c M Python/initconfig.c M Python/sysmodule.c diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 606e578a1f31..20e01c796685 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -121,7 +121,7 @@ Copyright (C) 1994 Steen Lumholt. #define WAIT_FOR_STDIN static PyObject * -_get_tcl_lib_path() +_get_tcl_lib_path(void) { static PyObject *tcl_library_path = NULL; static int already_checked = 0; diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index e38caf7cc0ab..dd150107e4a9 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -8546,7 +8546,7 @@ os_setpgrp_impl(PyObject *module) #include static PyObject* -win32_getppid() +win32_getppid(void) { DWORD error; PyObject* result = NULL; @@ -13330,7 +13330,7 @@ static int has_ShellExecute = -1; static HINSTANCE (CALLBACK *Py_ShellExecuteW)(HWND, LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR, INT); static int -check_ShellExecute() +check_ShellExecute(void) { HINSTANCE hShell32; diff --git a/PC/launcher.c b/PC/launcher.c index 0776e57249c4..dc265533740b 100644 --- a/PC/launcher.c +++ b/PC/launcher.c @@ -449,7 +449,7 @@ locate_pythons_for_key(HKEY root, REGSAM flags) } static void -locate_store_pythons() +locate_store_pythons(void) { #if defined(_M_X64) /* 64bit process, so look in native registry */ @@ -466,7 +466,7 @@ locate_store_pythons() } static void -locate_venv_python() +locate_venv_python(void) { static wchar_t venv_python[MAX_PATH]; INSTALLED_PYTHON * ip; @@ -495,7 +495,7 @@ locate_venv_python() } static void -locate_all_pythons() +locate_all_pythons(void) { /* venv Python is highest priority */ locate_venv_python(); @@ -694,7 +694,7 @@ static wchar_t wrapped_script_path[MAX_PATH]; * valid wrapped script file. */ static void -locate_wrapped_script() +locate_wrapped_script(void) { wchar_t * p; size_t plen; @@ -1034,7 +1034,7 @@ read_config_file(wchar_t * config_path) } } -static void read_commands() +static void read_commands(void) { if (launcher_ini_path[0]) read_config_file(launcher_ini_path); @@ -1684,7 +1684,7 @@ wcsdup_pad(const wchar_t *s, int padding, int *newlen) } static wchar_t * -get_process_name() +get_process_name(void) { DWORD bufferLen = MAX_PATH; DWORD len = bufferLen; diff --git a/PC/launcher2.c b/PC/launcher2.c index 932665387f19..bb500d4b6bfb 100644 --- a/PC/launcher2.c +++ b/PC/launcher2.c @@ -132,7 +132,7 @@ typedef BOOL (*PIsWow64Process2)(HANDLE, USHORT*, USHORT*); USHORT -_getNativeMachine() +_getNativeMachine(void) { static USHORT _nativeMachine = IMAGE_FILE_MACHINE_UNKNOWN; if (_nativeMachine == IMAGE_FILE_MACHINE_UNKNOWN) { @@ -163,14 +163,14 @@ _getNativeMachine() bool -isAMD64Host() +isAMD64Host(void) { return _getNativeMachine() == IMAGE_FILE_MACHINE_AMD64; } bool -isARM64Host() +isARM64Host(void) { return _getNativeMachine() == IMAGE_FILE_MACHINE_ARM64; } diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 749d8144bf7a..29796be4b80e 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -467,7 +467,7 @@ void _PyEval_SetSwitchInterval(unsigned long microseconds) gil->interval = microseconds; } -unsigned long _PyEval_GetSwitchInterval() +unsigned long _PyEval_GetSwitchInterval(void) { struct _gil_runtime_state *gil = &_PyRuntime.ceval.gil; return gil->interval; diff --git a/Python/initconfig.c b/Python/initconfig.c index db7f11e17d66..0d42b7ea082d 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -2355,13 +2355,13 @@ config_usage(int error, const wchar_t* program) } static void -config_envvars_usage() +config_envvars_usage(void) { printf(usage_envvars, (wint_t)DELIM, (wint_t)DELIM, PYTHONHOMEHELP); } static void -config_xoptions_usage() +config_xoptions_usage(void) { puts(usage_xoptions); } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 4afb0f1d0b5e..f1a294de5984 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1488,7 +1488,7 @@ static PyStructSequence_Desc windows_version_desc = { }; static PyObject * -_sys_getwindowsversion_from_kernel32() +_sys_getwindowsversion_from_kernel32(void) { #ifndef MS_WINDOWS_DESKTOP return NULL; From webhook-mailer at python.org Wed Apr 5 03:27:08 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Wed, 05 Apr 2023 07:27:08 -0000 Subject: [Python-checkins] gh-103193: Micro-optimise helper functions for `inspect.getattr_static` (#103195) Message-ID: https://github.com/python/cpython/commit/264c00a1c512a9bd58f47c80e72e436c639763c8 commit: 264c00a1c512a9bd58f47c80e72e436c639763c8 branch: main author: Alex Waygood committer: AlexWaygood date: 2023-04-05T08:27:01+01:00 summary: gh-103193: Micro-optimise helper functions for `inspect.getattr_static` (#103195) files: A Misc/NEWS.d/next/Library/2023-04-02-17-51-08.gh-issue-103193.xrZbM1.rst M Lib/inspect.py diff --git a/Lib/inspect.py b/Lib/inspect.py index 0eceaaf9a24f..8739c9c25726 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1772,9 +1772,9 @@ def trace(context=1): # ------------------------------------------------ static version of getattr _sentinel = object() +_static_getmro = type.__dict__['__mro__'].__get__ +_get_dunder_dict_of_class = type.__dict__["__dict__"].__get__ -def _static_getmro(klass): - return type.__dict__['__mro__'].__get__(klass) def _check_instance(obj, attr): instance_dict = {} @@ -1802,10 +1802,9 @@ def _is_type(obj): return True def _shadowed_dict(klass): - dict_attr = type.__dict__["__dict__"] for entry in _static_getmro(klass): try: - class_dict = dict_attr.__get__(entry)["__dict__"] + class_dict = _get_dunder_dict_of_class(entry)["__dict__"] except KeyError: pass else: diff --git a/Misc/NEWS.d/next/Library/2023-04-02-17-51-08.gh-issue-103193.xrZbM1.rst b/Misc/NEWS.d/next/Library/2023-04-02-17-51-08.gh-issue-103193.xrZbM1.rst new file mode 100644 index 000000000000..f0b76a605a56 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-02-17-51-08.gh-issue-103193.xrZbM1.rst @@ -0,0 +1,2 @@ +Improve performance of :func:`inspect.getattr_static`. Patch by Alex +Waygood. From webhook-mailer at python.org Wed Apr 5 05:07:38 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Wed, 05 Apr 2023 09:07:38 -0000 Subject: [Python-checkins] gh-74690: typing: Simplify and optimise `_ProtocolMeta.__instancecheck__` (#103159) Message-ID: https://github.com/python/cpython/commit/47753ecde21b79b5c5f11d883946fda2a340e427 commit: 47753ecde21b79b5c5f11d883946fda2a340e427 branch: main author: Alex Waygood committer: AlexWaygood date: 2023-04-05T10:07:30+01:00 summary: gh-74690: typing: Simplify and optimise `_ProtocolMeta.__instancecheck__` (#103159) files: M Lib/typing.py diff --git a/Lib/typing.py b/Lib/typing.py index 442d684d14c9..f50e9b0a93b0 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2024,20 +2024,12 @@ def __instancecheck__(cls, instance): raise TypeError("Instance and class checks can only be used with" " @runtime_checkable protocols") - if not is_protocol_cls and issubclass(instance.__class__, cls): - return True - - protocol_attrs = _get_protocol_attrs(cls) - - if ( - _is_callable_members_only(cls, protocol_attrs) - and issubclass(instance.__class__, cls) - ): + if super().__instancecheck__(instance): return True if is_protocol_cls: getattr_static = _lazy_load_getattr_static() - for attr in protocol_attrs: + for attr in _get_protocol_attrs(cls): try: val = getattr_static(instance, attr) except AttributeError: @@ -2047,7 +2039,7 @@ def __instancecheck__(cls, instance): else: return True - return super().__instancecheck__(instance) + return False class Protocol(Generic, metaclass=_ProtocolMeta): From webhook-mailer at python.org Wed Apr 5 07:17:12 2023 From: webhook-mailer at python.org (iritkatriel) Date: Wed, 05 Apr 2023 11:17:12 -0000 Subject: [Python-checkins] gh-81762: Clarify and simplify description of print's flush param (#103264) Message-ID: https://github.com/python/cpython/commit/c396b6ddf3da784349bac9ebf7f28c55bde016ea commit: c396b6ddf3da784349bac9ebf7f28c55bde016ea branch: main author: C.A.M. Gerlach committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-04-05T12:16:36+01:00 summary: gh-81762: Clarify and simplify description of print's flush param (#103264) files: M Doc/library/functions.rst diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index f0f374771b0c..8797485cd05d 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1444,8 +1444,9 @@ are always available. They are listed here in alphabetical order. arguments are converted to text strings, :func:`print` cannot be used with binary mode file objects. For these, use ``file.write(...)`` instead. - Whether the output is buffered is usually determined by *file*, but if the - *flush* keyword argument is true, the stream is forcibly flushed. + Output buffering is usually determined by *file*. + However, if *flush* is true, the stream is forcibly flushed. + .. versionchanged:: 3.3 Added the *flush* keyword argument. From webhook-mailer at python.org Wed Apr 5 07:17:16 2023 From: webhook-mailer at python.org (pablogsal) Date: Wed, 05 Apr 2023 11:17:16 -0000 Subject: [Python-checkins] Python 3.11.3 Message-ID: https://github.com/python/cpython/commit/f3909b8bc83675b7ab093dbc558e677558d8e718 commit: f3909b8bc83675b7ab093dbc558e677558d8e718 branch: 3.11 author: Pablo Galindo committer: pablogsal date: 2023-04-04T23:22:17+01:00 summary: Python 3.11.3 files: A Misc/NEWS.d/3.11.3.rst D Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-08-17-13-31.gh-issue-101696.seJhTt.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-10-07-21-47.gh-issue-101765.MO5LlC.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-16-23-19-01.gh-issue-101967.Kqr1dz.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-24-17-59-39.gh-issue-102126.HTT8Vc.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst D Misc/NEWS.d/next/Documentation/2023-02-07-21-43-24.gh-issue-97725.cuY7Cd.rst D Misc/NEWS.d/next/Documentation/2023-02-19-10-33-01.gh-issue-85417.kYO8u3.rst D Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst D Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst D Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst D Misc/NEWS.d/next/Library/2022-08-27-10-35-50.gh-issue-96127.8RdLre.rst D Misc/NEWS.d/next/Library/2022-09-05-12-17-34.gh-issue-88233.gff9qJ.rst D Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst D Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst D Misc/NEWS.d/next/Library/2023-02-10-16-02-29.gh-issue-101517.r7S2u8.rst D Misc/NEWS.d/next/Library/2023-02-11-13-23-29.gh-issue-97786.QjvQ1B.rst D Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst D Misc/NEWS.d/next/Library/2023-02-17-20-24-15.gh-issue-101566.FjgWBt.rst D Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst D Misc/NEWS.d/next/Library/2023-02-21-07-15-41.gh-issue-101936.QVOxHH.rst D Misc/NEWS.d/next/Library/2023-02-21-10-05-33.gh-issue-101961.7e56jh.rst D Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst D Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst D Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst D Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst D Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst D Misc/NEWS.d/next/Library/2023-03-27-19-21-51.gh-issue-102549.NQ6Nlv.rst D Misc/NEWS.d/next/Security/2023-01-24-16-12-00.gh-issue-101283.9tqu39.rst D Misc/NEWS.d/next/Security/2023-02-08-22-03-04.gh-issue-101727.9P5eZz.rst D Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst D Misc/NEWS.d/next/Tests/2023-02-11-20-28-08.gh-issue-89792.S-Y5BZ.rst D Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst D Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst D Misc/NEWS.d/next/Windows/2023-02-07-18-22-54.gh-issue-101614.NjVP0n.rst D Misc/NEWS.d/next/Windows/2023-02-09-22-09-27.gh-issue-101759.zFlqSH.rst D Misc/NEWS.d/next/Windows/2023-02-10-14-26-05.gh-issue-101763.RPaj7r.rst D Misc/NEWS.d/next/Windows/2023-02-13-16-32-50.gh-issue-101849.7lm_53.rst D Misc/NEWS.d/next/macOS/2023-02-09-22-07-17.gh-issue-101759.B0JP2H.rst D Misc/NEWS.d/next/macOS/2023-04-04-13-37-28.gh-issue-103207.x0vvQp.rst M Include/patchlevel.h M Lib/pydoc_data/topics.py M README.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index e0d27fcdcb64..55e2abbc232d 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -18,12 +18,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 11 -#define PY_MICRO_VERSION 2 +#define PY_MICRO_VERSION 3 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.11.2+" +#define PY_VERSION "3.11.3" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 7e3f4f9830d5..3d9e748fe132 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Tue Feb 7 13:37:35 2023 +# Autogenerated by Sphinx on Tue Apr 4 23:22:02 2023 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' @@ -1134,10 +1134,11 @@ 'future, a\n' ' check may be added to prevent this.\n' '\n' - '* Nonempty *__slots__* does not work for classes derived ' - 'from\n' - ' ?variable-length? built-in types such as "int", ' - '"bytes" and "tuple".\n' + '* "TypeError" will be raised if nonempty *__slots__* are ' + 'defined for a\n' + ' class derived from a ""variable-length" built-in type" ' + 'such as\n' + ' "int", "bytes", and "tuple".\n' '\n' '* Any non-string *iterable* may be assigned to ' '*__slots__*.\n' @@ -2499,42 +2500,33 @@ 'alive\n' 'until the next garbage collection occurs.\n' '\n' - 'Before an "except" clause?s suite is executed, details about ' - 'the\n' - 'exception are stored in the "sys" module and can be accessed ' - 'via\n' - '"sys.exc_info()". "sys.exc_info()" returns a 3-tuple consisting ' - 'of the\n' - 'exception class, the exception instance and a traceback object ' - '(see\n' - 'section The standard type hierarchy) identifying the point in ' - 'the\n' - 'program where the exception occurred. The details about the ' - 'exception\n' - 'accessed via "sys.exc_info()" are restored to their previous ' - 'values\n' - 'when leaving an exception handler:\n' + 'Before an "except" clause?s suite is executed, the exception is ' + 'stored\n' + 'in the "sys" module, where it can be accessed from within the ' + 'body of\n' + 'the "except" clause by calling "sys.exception()". When leaving ' + 'an\n' + 'exception handler, the exception stored in the "sys" module is ' + 'reset\n' + 'to its previous value:\n' '\n' - ' >>> print(sys.exc_info())\n' - ' (None, None, None)\n' + ' >>> print(sys.exception())\n' + ' None\n' ' >>> try:\n' ' ... raise TypeError\n' ' ... except:\n' - ' ... print(sys.exc_info())\n' + ' ... print(repr(sys.exception()))\n' ' ... try:\n' ' ... raise ValueError\n' ' ... except:\n' - ' ... print(sys.exc_info())\n' - ' ... print(sys.exc_info())\n' + ' ... print(repr(sys.exception()))\n' + ' ... print(repr(sys.exception()))\n' ' ...\n' - " (, TypeError(), )\n' - " (, ValueError(), )\n' - " (, TypeError(), )\n' - ' >>> print(sys.exc_info())\n' - ' (None, None, None)\n' + ' TypeError()\n' + ' ValueError()\n' + ' TypeError()\n' + ' >>> print(sys.exception())\n' + ' None\n' '\n' '\n' '"except*" clause\n' @@ -3081,7 +3073,7 @@ 'AS\n' 'pattern binds the subject to the name on the right of the as ' 'keyword\n' - 'and succeeds. "capture_pattern" cannot be a a "_".\n' + 'and succeeds. "capture_pattern" cannot be a "_".\n' '\n' 'In simple terms "P as NAME" will match with "P", and on success ' 'it\n' @@ -4533,7 +4525,7 @@ 'objects and\n' ' implements an "__eq__()" method, it should not ' 'implement\n' - ' "__hash__()", since the implementation of hashable ' + ' "__hash__()", since the implementation of *hashable* ' 'collections\n' ' requires that a key?s hash value is immutable (if the ' 'object?s hash\n' @@ -4684,7 +4676,7 @@ 'scripts. For\n' 'example:\n' '\n' - ' python3 -m pdb myscript.py\n' + ' python -m pdb myscript.py\n' '\n' 'When invoked as a script, pdb will automatically enter ' 'post-mortem\n' @@ -4704,7 +4696,7 @@ '\n' 'New in version 3.7: "pdb.py" now accepts a "-m" option that ' 'execute\n' - 'modules similar to the way "python3 -m" does. As with a script, ' + 'modules similar to the way "python -m" does. As with a script, ' 'the\n' 'debugger will pause execution just before the first line of the\n' 'module.\n' @@ -4768,8 +4760,8 @@ 'object)\n' ' under debugger control. When "runeval()" returns, it returns ' 'the\n' - ' value of the expression. Otherwise this function is similar ' - 'to\n' + ' value of the *expression*. Otherwise this function is ' + 'similar to\n' ' "run()".\n' '\n' 'pdb.runcall(function, *args, **kwds)\n' @@ -5031,14 +5023,15 @@ 'ignore bpnumber [count]\n' '\n' ' Set the ignore count for the given breakpoint number. If ' - 'count is\n' - ' omitted, the ignore count is set to 0. A breakpoint becomes ' - 'active\n' - ' when the ignore count is zero. When non-zero, the count is\n' - ' decremented each time the breakpoint is reached and the ' - 'breakpoint\n' - ' is not disabled and any associated condition evaluates to ' - 'true.\n' + '*count*\n' + ' is omitted, the ignore count is set to 0. A breakpoint ' + 'becomes\n' + ' active when the ignore count is zero. When non-zero, the ' + '*count*\n' + ' is decremented each time the breakpoint is reached and the\n' + ' breakpoint is not disabled and any associated condition ' + 'evaluates\n' + ' to true.\n' '\n' 'condition bpnumber [condition]\n' '\n' @@ -5088,7 +5081,7 @@ ' breakpoint?which could have its own command list, leading to\n' ' ambiguities about which list to execute.\n' '\n' - ' If you use the ?silent? command in the command list, the ' + ' If you use the "silent" command in the command list, the ' 'usual\n' ' message about stopping at a breakpoint is not printed. This ' 'may be\n' @@ -5123,11 +5116,10 @@ 'number\n' ' greater than the current one is reached.\n' '\n' - ' With a line number, continue execution until a line with a ' - 'number\n' - ' greater or equal to that is reached. In both cases, also ' - 'stop when\n' - ' the current frame returns.\n' + ' With *lineno*, continue execution until a line with a number\n' + ' greater or equal to *lineno* is reached. In both cases, also ' + 'stop\n' + ' when the current frame returns.\n' '\n' ' Changed in version 3.2: Allow giving an explicit line ' 'number.\n' @@ -5191,9 +5183,8 @@ '\n' 'p expression\n' '\n' - ' Evaluate the *expression* in the current context and print ' - 'its\n' - ' value.\n' + ' Evaluate *expression* in the current context and print its ' + 'value.\n' '\n' ' Note:\n' '\n' @@ -5203,26 +5194,26 @@ '\n' 'pp expression\n' '\n' - ' Like the "p" command, except the value of the expression is ' + ' Like the "p" command, except the value of *expression* is ' 'pretty-\n' ' printed using the "pprint" module.\n' '\n' 'whatis expression\n' '\n' - ' Print the type of the *expression*.\n' + ' Print the type of *expression*.\n' '\n' 'source expression\n' '\n' - ' Try to get source code for the given object and display it.\n' + ' Try to get source code of *expression* and display it.\n' '\n' ' New in version 3.2.\n' '\n' 'display [expression]\n' '\n' - ' Display the value of the expression if it changed, each time\n' + ' Display the value of *expression* if it changed, each time\n' ' execution stops in the current frame.\n' '\n' - ' Without expression, list all display expressions for the ' + ' Without *expression*, list all display expressions for the ' 'current\n' ' frame.\n' '\n' @@ -5230,10 +5221,10 @@ '\n' 'undisplay [expression]\n' '\n' - ' Do not display the expression any more in the current frame.\n' - ' Without expression, clear all display expressions for the ' - 'current\n' - ' frame.\n' + ' Do not display *expression* anymore in the current frame. ' + 'Without\n' + ' *expression*, clear all display expressions for the current ' + 'frame.\n' '\n' ' New in version 3.2.\n' '\n' @@ -5249,16 +5240,16 @@ '\n' 'alias [name [command]]\n' '\n' - ' Create an alias called *name* that executes *command*. The ' - 'command\n' - ' must *not* be enclosed in quotes. Replaceable parameters can ' - 'be\n' - ' indicated by "%1", "%2", and so on, while "%*" is replaced by ' - 'all\n' - ' the parameters. If no command is given, the current alias ' - 'for\n' - ' *name* is shown. If no arguments are given, all aliases are ' - 'listed.\n' + ' Create an alias called *name* that executes *command*. The\n' + ' *command* must *not* be enclosed in quotes. Replaceable ' + 'parameters\n' + ' can be indicated by "%1", "%2", and so on, while "%*" is ' + 'replaced\n' + ' by all the parameters. If *command* is omitted, the current ' + 'alias\n' + ' for *name* is shown. If no arguments are given, all aliases ' + 'are\n' + ' listed.\n' '\n' ' Aliases may be nested and can contain anything that can be ' 'legally\n' @@ -5277,14 +5268,14 @@ ' in the ".pdbrc" file):\n' '\n' ' # Print instance variables (usage "pi classInst")\n' - ' alias pi for k in %1.__dict__.keys(): ' - 'print("%1.",k,"=",%1.__dict__[k])\n' + ' alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = ' + '{%1.__dict__[k]}")\n' ' # Print instance variables in self\n' ' alias ps pi self\n' '\n' 'unalias name\n' '\n' - ' Delete the specified alias.\n' + ' Delete the specified alias *name*.\n' '\n' '! statement\n' '\n' @@ -5304,12 +5295,13 @@ 'run [args ...]\n' 'restart [args ...]\n' '\n' - ' Restart the debugged Python program. If an argument is ' - 'supplied,\n' - ' it is split with "shlex" and the result is used as the new\n' - ' "sys.argv". History, breakpoints, actions and debugger ' - 'options are\n' - ' preserved. "restart" is an alias for "run".\n' + ' Restart the debugged Python program. If *args* is supplied, ' + 'it is\n' + ' split with "shlex" and the result is used as the new ' + '"sys.argv".\n' + ' History, breakpoints, actions and debugger options are ' + 'preserved.\n' + ' "restart" is an alias for "run".\n' '\n' 'q(uit)\n' '\n' @@ -5318,11 +5310,11 @@ '\n' 'debug code\n' '\n' - ' Enter a recursive debugger that steps through the code ' - 'argument\n' - ' (which is an arbitrary expression or statement to be executed ' - 'in\n' - ' the current environment).\n' + ' Enter a recursive debugger that steps through *code* (which ' + 'is an\n' + ' arbitrary expression or statement to be executed in the ' + 'current\n' + ' environment).\n' '\n' 'retval\n' '\n' @@ -6179,7 +6171,8 @@ 'The general form of a *standard format specifier* is:\n' '\n' ' format_spec ::= ' - '[[fill]align][sign][z][#][0][width][grouping_option][.precision][type]\n' + '[[fill]align][sign]["z"]["#"]["0"][width][grouping_option]["." ' + 'precision][type]\n' ' fill ::= \n' ' align ::= "<" | ">" | "=" | "^"\n' ' sign ::= "+" | "-" | " "\n' @@ -9453,7 +9446,7 @@ ' hashable collections. If a class defines mutable objects ' 'and\n' ' implements an "__eq__()" method, it should not implement\n' - ' "__hash__()", since the implementation of hashable ' + ' "__hash__()", since the implementation of *hashable* ' 'collections\n' ' requires that a key?s hash value is immutable (if the ' 'object?s hash\n' @@ -9990,10 +9983,11 @@ 'future, a\n' ' check may be added to prevent this.\n' '\n' - '* Nonempty *__slots__* does not work for classes derived ' - 'from\n' - ' ?variable-length? built-in types such as "int", "bytes" ' - 'and "tuple".\n' + '* "TypeError" will be raised if nonempty *__slots__* are ' + 'defined for a\n' + ' class derived from a ""variable-length" built-in type" ' + 'such as\n' + ' "int", "bytes", and "tuple".\n' '\n' '* Any non-string *iterable* may be assigned to *__slots__*.\n' '\n' @@ -12635,37 +12629,31 @@ 'cycle with the stack frame, keeping all locals in that frame alive\n' 'until the next garbage collection occurs.\n' '\n' - 'Before an "except" clause?s suite is executed, details about the\n' - 'exception are stored in the "sys" module and can be accessed via\n' - '"sys.exc_info()". "sys.exc_info()" returns a 3-tuple consisting of ' - 'the\n' - 'exception class, the exception instance and a traceback object (see\n' - 'section The standard type hierarchy) identifying the point in the\n' - 'program where the exception occurred. The details about the ' - 'exception\n' - 'accessed via "sys.exc_info()" are restored to their previous values\n' - 'when leaving an exception handler:\n' + 'Before an "except" clause?s suite is executed, the exception is ' + 'stored\n' + 'in the "sys" module, where it can be accessed from within the body ' + 'of\n' + 'the "except" clause by calling "sys.exception()". When leaving an\n' + 'exception handler, the exception stored in the "sys" module is reset\n' + 'to its previous value:\n' '\n' - ' >>> print(sys.exc_info())\n' - ' (None, None, None)\n' + ' >>> print(sys.exception())\n' + ' None\n' ' >>> try:\n' ' ... raise TypeError\n' ' ... except:\n' - ' ... print(sys.exc_info())\n' + ' ... print(repr(sys.exception()))\n' ' ... try:\n' ' ... raise ValueError\n' ' ... except:\n' - ' ... print(sys.exc_info())\n' - ' ... print(sys.exc_info())\n' + ' ... print(repr(sys.exception()))\n' + ' ... print(repr(sys.exception()))\n' ' ...\n' - " (, TypeError(), )\n' - " (, ValueError(), )\n' - " (, TypeError(), )\n' - ' >>> print(sys.exc_info())\n' - ' (None, None, None)\n' + ' TypeError()\n' + ' ValueError()\n' + ' TypeError()\n' + ' >>> print(sys.exception())\n' + ' None\n' '\n' '\n' '"except*" clause\n' @@ -14398,7 +14386,7 @@ ' New in version 3.10.\n' '\n' 'Keys views are set-like since their entries are unique and ' - 'hashable.\n' + '*hashable*.\n' 'If all values are hashable, so that "(key, value)" pairs are ' 'unique\n' 'and hashable, then the items view is also set-like. (Values ' diff --git a/Misc/NEWS.d/3.11.3.rst b/Misc/NEWS.d/3.11.3.rst new file mode 100644 index 000000000000..d74dae3b9551 --- /dev/null +++ b/Misc/NEWS.d/3.11.3.rst @@ -0,0 +1,466 @@ +.. date: 2023-02-08-22-03-04 +.. gh-issue: 101727 +.. nonce: 9P5eZz +.. release date: 2023-04-04 +.. section: Security + +Updated the OpenSSL version used in Windows and macOS binary release builds +to 1.1.1t to address CVE-2023-0286, CVE-2022-4303, and CVE-2022-4303 per +`the OpenSSL 2023-02-07 security advisory +`_. + +.. + +.. date: 2023-01-24-16-12-00 +.. gh-issue: 101283 +.. nonce: 9tqu39 +.. section: Security + +:class:`subprocess.Popen` now uses a safer approach to find ``cmd.exe`` when +launching with ``shell=True``. Patch by Eryk Sun, based on a patch by Oleg +Iarygin. + +.. + +.. date: 2023-03-18-02-36-39 +.. gh-issue: 101975 +.. nonce: HwMR1d +.. section: Core and Builtins + +Fixed ``stacktop`` value on tracing entries to avoid corruption on garbage +collection. + +.. + +.. date: 2023-03-16-17-24-44 +.. gh-issue: 102701 +.. nonce: iNGVaS +.. section: Core and Builtins + +Fix overflow when creating very large dict. + +.. + +.. date: 2023-03-06-13-05-33 +.. gh-issue: 102416 +.. nonce: dz6K5f +.. section: Core and Builtins + +Do not memoize incorrectly automatically generated loop rules in the parser. +Patch by Pablo Galindo. + +.. + +.. date: 2023-03-04-20-56-12 +.. gh-issue: 102356 +.. nonce: 07KvUd +.. section: Core and Builtins + +Fix a bug that caused a crash when deallocating deeply nested filter +objects. Patch by Marta G?mez Mac?as. + +.. + +.. date: 2023-03-04-06-48-34 +.. gh-issue: 102397 +.. nonce: ACJaOf +.. section: Core and Builtins + +Fix segfault from race condition in signal handling during garbage +collection. Patch by Kumar Aditya. + +.. + +.. date: 2023-03-02-13-49-21 +.. gh-issue: 102281 +.. nonce: QCuu2N +.. section: Core and Builtins + +Fix potential nullptr dereference and use of uninitialized memory in +fileutils. Patch by Max Bachmann. + +.. + +.. date: 2023-02-24-17-59-39 +.. gh-issue: 102126 +.. nonce: HTT8Vc +.. section: Core and Builtins + +Fix deadlock at shutdown when clearing thread states if any finalizer tries +to acquire the runtime head lock. Patch by Kumar Aditya. + +.. + +.. date: 2023-02-21-23-42-39 +.. gh-issue: 102027 +.. nonce: fQARG0 +.. section: Core and Builtins + +Fix SSE2 and SSE3 detection in ``_blake2`` internal module. Patch by Max +Bachmann. + +.. + +.. date: 2023-02-16-23-19-01 +.. gh-issue: 101967 +.. nonce: Kqr1dz +.. section: Core and Builtins + +Fix possible segfault in ``positional_only_passed_as_keyword`` function, +when new list created. + +.. + +.. date: 2023-02-10-07-21-47 +.. gh-issue: 101765 +.. nonce: MO5LlC +.. section: Core and Builtins + +Fix SystemError / segmentation fault in iter ``__reduce__`` when internal +access of ``builtins.__dict__`` keys mutates the iter object. + +.. + +.. date: 2023-02-08-17-13-31 +.. gh-issue: 101696 +.. nonce: seJhTt +.. section: Core and Builtins + +Invalidate type version tag in ``_PyStaticType_Dealloc`` for static types, +avoiding bug where a false cache hit could crash the interpreter. Patch by +Kumar Aditya. + +.. + +.. date: 2023-03-27-19-21-51 +.. gh-issue: 102549 +.. nonce: NQ6Nlv +.. section: Library + +Don't ignore exceptions in member type creation. + +.. + +.. date: 2023-03-23-13-34-33 +.. gh-issue: 102947 +.. nonce: cTwcpU +.. section: Library + +Improve traceback when :func:`dataclasses.fields` is called on a +non-dataclass. Patch by Alex Waygood + +.. + +.. date: 2023-03-22-16-15-18 +.. gh-issue: 102780 +.. nonce: NEcljy +.. section: Library + +The :class:`asyncio.Timeout` context manager now works reliably even when +performing cleanup due to task cancellation. Previously it could raise a +:exc:`~asyncio.CancelledError` instead of an :exc:`~asyncio.TimeoutError` in +such cases. + +.. + +.. date: 2023-03-18-14-59-21 +.. gh-issue: 88965 +.. nonce: kA70Km +.. section: Library + +typing: Fix a bug relating to substitution in custom classes generic over a +:class:`~typing.ParamSpec`. Previously, if the ``ParamSpec`` was substituted +with a parameters list that itself contained a :class:`~typing.TypeVar`, the +``TypeVar`` in the parameters list could not be subsequently substituted. +This is now fixed. + +Patch by Nikita Sobolev. + +.. + +.. date: 2023-02-28-09-52-25 +.. gh-issue: 101979 +.. nonce: or3hXV +.. section: Library + +Fix a bug where parentheses in the ``metavar`` argument to +:meth:`argparse.ArgumentParser.add_argument` were dropped. Patch by Yeojin +Kim. + +.. + +.. date: 2023-02-23-15-06-01 +.. gh-issue: 102179 +.. nonce: P6KQ4c +.. section: Library + +Fix :func:`os.dup2` error message for negative fds. + +.. + +.. date: 2023-02-21-10-05-33 +.. gh-issue: 101961 +.. nonce: 7e56jh +.. section: Library + +For the binary mode, :func:`fileinput.hookcompressed` doesn't set the +``encoding`` value even if the value is ``None``. Patch by Gihwan Kim. + +.. + +.. date: 2023-02-21-07-15-41 +.. gh-issue: 101936 +.. nonce: QVOxHH +.. section: Library + +The default value of ``fp`` becomes :class:`io.BytesIO` if +:exc:`~urllib.error.HTTPError` is initialized without a designated ``fp`` +parameter. Patch by Long Vo. + +.. + +.. date: 2023-02-20-16-47-56 +.. gh-issue: 102069 +.. nonce: FS7f1j +.. section: Library + +Fix ``__weakref__`` descriptor generation for custom dataclasses. + +.. + +.. date: 2023-02-17-20-24-15 +.. gh-issue: 101566 +.. nonce: FjgWBt +.. section: Library + +In zipfile, apply fix for extractall on the underlying zipfile after being +wrapped in ``Path``. + +.. + +.. date: 2023-02-14-09-08-48 +.. gh-issue: 101892 +.. nonce: FMos8l +.. section: Library + +Callable iterators no longer raise :class:`SystemError` when the callable +object exhausts the iterator but forgets to either return a sentinel value +or raise :class:`StopIteration`. + +.. + +.. date: 2023-02-11-13-23-29 +.. gh-issue: 97786 +.. nonce: QjvQ1B +.. section: Library + +Fix potential undefined behaviour in corner cases of floating-point-to-time +conversions. + +.. + +.. date: 2023-02-10-16-02-29 +.. gh-issue: 101517 +.. nonce: r7S2u8 +.. section: Library + +Fixed bug where :mod:`bdb` looks up the source line with :mod:`linecache` +with a ``lineno=None``, which causes it to fail with an unhandled exception. + +.. + +.. date: 2023-02-09-19-40-41 +.. gh-issue: 101673 +.. nonce: mX-Ppq +.. section: Library + +Fix a :mod:`pdb` bug where ``ll`` clears the changes to local variables. + +.. + +.. date: 2022-09-19-08-12-58 +.. gh-issue: 96931 +.. nonce: x0WQhh +.. section: Library + +Fix incorrect results from :meth:`ssl.SSLSocket.shared_ciphers` + +.. + +.. date: 2022-09-05-12-17-34 +.. gh-issue: 88233 +.. nonce: gff9qJ +.. section: Library + +Correctly preserve "extra" fields in ``zipfile`` regardless of their +ordering relative to a zip64 "extra." + +.. + +.. date: 2022-08-27-10-35-50 +.. gh-issue: 96127 +.. nonce: 8RdLre +.. section: Library + +``inspect.signature`` was raising ``TypeError`` on call with mock objects. +Now it correctly returns ``(*args, **kwargs)`` as infered signature. + +.. + +.. date: 2022-07-30-23-01-43 +.. gh-issue: 95495 +.. nonce: RA-q1d +.. section: Library + +When built against OpenSSL 3.0, the :mod:`ssl` module had a bug where it +reported unauthenticated EOFs (i.e. without close_notify) as a clean +TLS-level EOF. It now raises :exc:`~ssl.SSLEOFError`, matching the behavior +in previous versions of OpenSSL. The :attr:`~ssl.SSLContext.options` +attribute on :class:`~ssl.SSLContext` also no longer includes +:data:`~ssl.OP_IGNORE_UNEXPECTED_EOF` by default. This option may be set to +specify the previous OpenSSL 3.0 behavior. + +.. + +.. date: 2022-06-30-21-28-41 +.. gh-issue: 94440 +.. nonce: LtgX0d +.. section: Library + +Fix a :mod:`concurrent.futures.process` bug where ``ProcessPoolExecutor`` +shutdown could hang after a future has been quickly submitted and canceled. + +.. + +.. date: 2023-03-29-14-51-39 +.. gh-issue: 103112 +.. nonce: XgGSEO +.. section: Documentation + +Add docstring to :meth:`http.client.HTTPResponse.read` to fix ``pydoc`` +output. + +.. + +.. date: 2023-02-19-10-33-01 +.. gh-issue: 85417 +.. nonce: kYO8u3 +.. section: Documentation + +Update :mod:`cmath` documentation to clarify behaviour on branch cuts. + +.. + +.. date: 2023-02-07-21-43-24 +.. gh-issue: 97725 +.. nonce: cuY7Cd +.. section: Documentation + +Fix :meth:`asyncio.Task.print_stack` description for ``file=None``. Patch by +Oleg Iarygin. + +.. + +.. date: 2023-03-23-23-25-18 +.. gh-issue: 102980 +.. nonce: Zps4QF +.. section: Tests + +Improve test coverage on :mod:`pdb`. + +.. + +.. date: 2023-03-08-13-54-20 +.. gh-issue: 102537 +.. nonce: Vfplpb +.. section: Tests + +Adjust the error handling strategy in +``test_zoneinfo.TzPathTest.python_tzpath_context``. Patch by Paul Ganssle. + +.. + +.. date: 2023-02-11-20-28-08 +.. gh-issue: 89792 +.. nonce: S-Y5BZ +.. section: Tests + +``test_tools`` now copies up to 10x less source data to a temporary +directory during the ``freeze`` test by ignoring git metadata and other +artifacts. It also limits its python build parallelism based on +os.cpu_count instead of hard coding it as 8 cores. + +.. + +.. date: 2023-01-27-18-10-40 +.. gh-issue: 101377 +.. nonce: IJGpqh +.. section: Tests + +Improved test_locale_calendar_formatweekday of calendar. + +.. + +.. date: 2023-03-15-02-03-39 +.. gh-issue: 102711 +.. nonce: zTkjts +.. section: Build + +Fix ``-Wstrict-prototypes`` compiler warnings. + +.. + +.. date: 2023-02-13-16-32-50 +.. gh-issue: 101849 +.. nonce: 7lm_53 +.. section: Windows + +Ensures installer will correctly upgrade existing ``py.exe`` launcher +installs. + +.. + +.. date: 2023-02-10-14-26-05 +.. gh-issue: 101763 +.. nonce: RPaj7r +.. section: Windows + +Updates copy of libffi bundled with Windows installs to 3.4.4. + +.. + +.. date: 2023-02-09-22-09-27 +.. gh-issue: 101759 +.. nonce: zFlqSH +.. section: Windows + +Update Windows installer to SQLite 3.40.1. + +.. + +.. date: 2023-02-07-18-22-54 +.. gh-issue: 101614 +.. nonce: NjVP0n +.. section: Windows + +Correctly handle extensions built against debug binaries that reference +``python3_d.dll``. + +.. + +.. date: 2023-04-04-13-37-28 +.. gh-issue: 103207 +.. nonce: x0vvQp +.. section: macOS + +Add instructions to the macOS installer welcome display on how to workaround +the macOS 13 Ventura ?The installer encountered an error? failure. + +.. + +.. date: 2023-02-09-22-07-17 +.. gh-issue: 101759 +.. nonce: B0JP2H +.. section: macOS + +Update macOS installer to SQLite 3.40.1. diff --git a/Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst b/Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst deleted file mode 100644 index 511843968777..000000000000 --- a/Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst +++ /dev/null @@ -1 +0,0 @@ -Fix ``-Wstrict-prototypes`` compiler warnings. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-08-17-13-31.gh-issue-101696.seJhTt.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-08-17-13-31.gh-issue-101696.seJhTt.rst deleted file mode 100644 index ff2bbb4b5642..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-08-17-13-31.gh-issue-101696.seJhTt.rst +++ /dev/null @@ -1 +0,0 @@ -Invalidate type version tag in ``_PyStaticType_Dealloc`` for static types, avoiding bug where a false cache hit could crash the interpreter. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-10-07-21-47.gh-issue-101765.MO5LlC.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-10-07-21-47.gh-issue-101765.MO5LlC.rst deleted file mode 100644 index cc99779a944e..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-10-07-21-47.gh-issue-101765.MO5LlC.rst +++ /dev/null @@ -1 +0,0 @@ -Fix SystemError / segmentation fault in iter ``__reduce__`` when internal access of ``builtins.__dict__`` keys mutates the iter object. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-16-23-19-01.gh-issue-101967.Kqr1dz.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-16-23-19-01.gh-issue-101967.Kqr1dz.rst deleted file mode 100644 index 6e681f910f53..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-16-23-19-01.gh-issue-101967.Kqr1dz.rst +++ /dev/null @@ -1 +0,0 @@ -Fix possible segfault in ``positional_only_passed_as_keyword`` function, when new list created. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst deleted file mode 100644 index 42d96b54677e..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix SSE2 and SSE3 detection in ``_blake2`` internal module. Patch by Max -Bachmann. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-24-17-59-39.gh-issue-102126.HTT8Vc.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-24-17-59-39.gh-issue-102126.HTT8Vc.rst deleted file mode 100644 index 68c43688c3df..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-24-17-59-39.gh-issue-102126.HTT8Vc.rst +++ /dev/null @@ -1 +0,0 @@ -Fix deadlock at shutdown when clearing thread states if any finalizer tries to acquire the runtime head lock. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst deleted file mode 100644 index b0269dd3d92b..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst +++ /dev/null @@ -1 +0,0 @@ -Fix potential nullptr dereference and use of uninitialized memory in fileutils. Patch by Max Bachmann. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst deleted file mode 100644 index db0b3f32c2ec..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix segfault from race condition in signal handling during garbage collection. -Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst deleted file mode 100644 index c03fd5266bc3..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a bug that caused a crash when deallocating deeply nested filter -objects. Patch by Marta G?mez Mac?as. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst deleted file mode 100644 index 9ffc67cfb7ed..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst +++ /dev/null @@ -1 +0,0 @@ -Do not memoize incorrectly automatically generated loop rules in the parser. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst deleted file mode 100644 index 4e1f31893377..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst +++ /dev/null @@ -1 +0,0 @@ -Fix overflow when creating very large dict. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst deleted file mode 100644 index 28c9a8465180..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed ``stacktop`` value on tracing entries to avoid corruption on garbage collection. diff --git a/Misc/NEWS.d/next/Documentation/2023-02-07-21-43-24.gh-issue-97725.cuY7Cd.rst b/Misc/NEWS.d/next/Documentation/2023-02-07-21-43-24.gh-issue-97725.cuY7Cd.rst deleted file mode 100644 index fd9ea049c239..000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-02-07-21-43-24.gh-issue-97725.cuY7Cd.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :meth:`asyncio.Task.print_stack` description for ``file=None``. -Patch by Oleg Iarygin. diff --git a/Misc/NEWS.d/next/Documentation/2023-02-19-10-33-01.gh-issue-85417.kYO8u3.rst b/Misc/NEWS.d/next/Documentation/2023-02-19-10-33-01.gh-issue-85417.kYO8u3.rst deleted file mode 100644 index a5532df14795..000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-02-19-10-33-01.gh-issue-85417.kYO8u3.rst +++ /dev/null @@ -1 +0,0 @@ -Update :mod:`cmath` documentation to clarify behaviour on branch cuts. diff --git a/Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst b/Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst deleted file mode 100644 index babc81509661..000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst +++ /dev/null @@ -1 +0,0 @@ -Add docstring to :meth:`http.client.HTTPResponse.read` to fix ``pydoc`` output. diff --git a/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst b/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst deleted file mode 100644 index 3eee82e59dfa..000000000000 --- a/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a :mod:`concurrent.futures.process` bug where ``ProcessPoolExecutor`` shutdown -could hang after a future has been quickly submitted and canceled. diff --git a/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst b/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst deleted file mode 100644 index d0f4ccbdd3e3..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst +++ /dev/null @@ -1,7 +0,0 @@ -When built against OpenSSL 3.0, the :mod:`ssl` module had a bug where it -reported unauthenticated EOFs (i.e. without close_notify) as a clean TLS-level -EOF. It now raises :exc:`~ssl.SSLEOFError`, matching the behavior in previous -versions of OpenSSL. The :attr:`~ssl.SSLContext.options` attribute on -:class:`~ssl.SSLContext` also no longer includes -:data:`~ssl.OP_IGNORE_UNEXPECTED_EOF` by default. This option may be set to -specify the previous OpenSSL 3.0 behavior. diff --git a/Misc/NEWS.d/next/Library/2022-08-27-10-35-50.gh-issue-96127.8RdLre.rst b/Misc/NEWS.d/next/Library/2022-08-27-10-35-50.gh-issue-96127.8RdLre.rst deleted file mode 100644 index 79edd8fd5d8f..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-27-10-35-50.gh-issue-96127.8RdLre.rst +++ /dev/null @@ -1,2 +0,0 @@ -``inspect.signature`` was raising ``TypeError`` on call with mock objects. -Now it correctly returns ``(*args, **kwargs)`` as infered signature. diff --git a/Misc/NEWS.d/next/Library/2022-09-05-12-17-34.gh-issue-88233.gff9qJ.rst b/Misc/NEWS.d/next/Library/2022-09-05-12-17-34.gh-issue-88233.gff9qJ.rst deleted file mode 100644 index 806f7011edc3..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-05-12-17-34.gh-issue-88233.gff9qJ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Correctly preserve "extra" fields in ``zipfile`` regardless of their -ordering relative to a zip64 "extra." diff --git a/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst b/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst deleted file mode 100644 index 766b1d4d477b..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst +++ /dev/null @@ -1 +0,0 @@ -Fix incorrect results from :meth:`ssl.SSLSocket.shared_ciphers` diff --git a/Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst b/Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst deleted file mode 100644 index 4e673ba98115..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a :mod:`pdb` bug where ``ll`` clears the changes to local variables. diff --git a/Misc/NEWS.d/next/Library/2023-02-10-16-02-29.gh-issue-101517.r7S2u8.rst b/Misc/NEWS.d/next/Library/2023-02-10-16-02-29.gh-issue-101517.r7S2u8.rst deleted file mode 100644 index a5f6bdfa5ac2..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-10-16-02-29.gh-issue-101517.r7S2u8.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed bug where :mod:`bdb` looks up the source line with :mod:`linecache` with a ``lineno=None``, which causes it to fail with an unhandled exception. diff --git a/Misc/NEWS.d/next/Library/2023-02-11-13-23-29.gh-issue-97786.QjvQ1B.rst b/Misc/NEWS.d/next/Library/2023-02-11-13-23-29.gh-issue-97786.QjvQ1B.rst deleted file mode 100644 index df194b67590d..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-11-13-23-29.gh-issue-97786.QjvQ1B.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix potential undefined behaviour in corner cases of floating-point-to-time -conversions. diff --git a/Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst b/Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst deleted file mode 100644 index d586779b3a8a..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst +++ /dev/null @@ -1,3 +0,0 @@ -Callable iterators no longer raise :class:`SystemError` when the -callable object exhausts the iterator but forgets to either return a -sentinel value or raise :class:`StopIteration`. diff --git a/Misc/NEWS.d/next/Library/2023-02-17-20-24-15.gh-issue-101566.FjgWBt.rst b/Misc/NEWS.d/next/Library/2023-02-17-20-24-15.gh-issue-101566.FjgWBt.rst deleted file mode 100644 index f0c0c249a54b..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-17-20-24-15.gh-issue-101566.FjgWBt.rst +++ /dev/null @@ -1,3 +0,0 @@ -In zipfile, apply -fix for extractall on the underlying zipfile after being wrapped in -``Path``. diff --git a/Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst b/Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst deleted file mode 100644 index 04c87e515cca..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst +++ /dev/null @@ -1 +0,0 @@ -Fix ``__weakref__`` descriptor generation for custom dataclasses. diff --git a/Misc/NEWS.d/next/Library/2023-02-21-07-15-41.gh-issue-101936.QVOxHH.rst b/Misc/NEWS.d/next/Library/2023-02-21-07-15-41.gh-issue-101936.QVOxHH.rst deleted file mode 100644 index 55841da44b11..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-21-07-15-41.gh-issue-101936.QVOxHH.rst +++ /dev/null @@ -1,2 +0,0 @@ -The default value of ``fp`` becomes :class:`io.BytesIO` if :exc:`~urllib.error.HTTPError` -is initialized without a designated ``fp`` parameter. Patch by Long Vo. diff --git a/Misc/NEWS.d/next/Library/2023-02-21-10-05-33.gh-issue-101961.7e56jh.rst b/Misc/NEWS.d/next/Library/2023-02-21-10-05-33.gh-issue-101961.7e56jh.rst deleted file mode 100644 index a3d4119e7cbd..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-21-10-05-33.gh-issue-101961.7e56jh.rst +++ /dev/null @@ -1,2 +0,0 @@ -For the binary mode, :func:`fileinput.hookcompressed` doesn't set the ``encoding`` value -even if the value is ``None``. Patch by Gihwan Kim. diff --git a/Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst b/Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst deleted file mode 100644 index f77493e267ac..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :func:`os.dup2` error message for negative fds. diff --git a/Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst b/Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst deleted file mode 100644 index 1efe72439b3a..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a bug where parentheses in the ``metavar`` argument to :meth:`argparse.ArgumentParser.add_argument` were -dropped. Patch by Yeojin Kim. diff --git a/Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst b/Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst deleted file mode 100644 index 6e9642100cd8..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst +++ /dev/null @@ -1,7 +0,0 @@ -typing: Fix a bug relating to substitution in custom classes generic over a -:class:`~typing.ParamSpec`. Previously, if the ``ParamSpec`` was substituted -with a parameters list that itself contained a :class:`~typing.TypeVar`, the -``TypeVar`` in the parameters list could not be subsequently substituted. This -is now fixed. - -Patch by Nikita Sobolev. diff --git a/Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst b/Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst deleted file mode 100644 index 2aaffe34b864..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst +++ /dev/null @@ -1,3 +0,0 @@ -The :class:`asyncio.Timeout` context manager now works reliably even when performing cleanup due -to task cancellation. Previously it could raise a -:exc:`~asyncio.CancelledError` instead of an :exc:`~asyncio.TimeoutError` in such cases. diff --git a/Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst b/Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst deleted file mode 100644 index b59c98203566..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve traceback when :func:`dataclasses.fields` is called on a -non-dataclass. Patch by Alex Waygood diff --git a/Misc/NEWS.d/next/Library/2023-03-27-19-21-51.gh-issue-102549.NQ6Nlv.rst b/Misc/NEWS.d/next/Library/2023-03-27-19-21-51.gh-issue-102549.NQ6Nlv.rst deleted file mode 100644 index e4def038175b..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-27-19-21-51.gh-issue-102549.NQ6Nlv.rst +++ /dev/null @@ -1 +0,0 @@ -Don't ignore exceptions in member type creation. diff --git a/Misc/NEWS.d/next/Security/2023-01-24-16-12-00.gh-issue-101283.9tqu39.rst b/Misc/NEWS.d/next/Security/2023-01-24-16-12-00.gh-issue-101283.9tqu39.rst deleted file mode 100644 index 0efdfa102341..000000000000 --- a/Misc/NEWS.d/next/Security/2023-01-24-16-12-00.gh-issue-101283.9tqu39.rst +++ /dev/null @@ -1,3 +0,0 @@ -:class:`subprocess.Popen` now uses a safer approach to find -``cmd.exe`` when launching with ``shell=True``. Patch by Eryk Sun, -based on a patch by Oleg Iarygin. diff --git a/Misc/NEWS.d/next/Security/2023-02-08-22-03-04.gh-issue-101727.9P5eZz.rst b/Misc/NEWS.d/next/Security/2023-02-08-22-03-04.gh-issue-101727.9P5eZz.rst deleted file mode 100644 index 43acc82063fd..000000000000 --- a/Misc/NEWS.d/next/Security/2023-02-08-22-03-04.gh-issue-101727.9P5eZz.rst +++ /dev/null @@ -1,4 +0,0 @@ -Updated the OpenSSL version used in Windows and macOS binary release builds -to 1.1.1t to address CVE-2023-0286, CVE-2022-4303, and CVE-2022-4303 per -`the OpenSSL 2023-02-07 security advisory -`_. diff --git a/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst b/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst deleted file mode 100644 index a9c19ce060e3..000000000000 --- a/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst +++ /dev/null @@ -1 +0,0 @@ -Improved test_locale_calendar_formatweekday of calendar. diff --git a/Misc/NEWS.d/next/Tests/2023-02-11-20-28-08.gh-issue-89792.S-Y5BZ.rst b/Misc/NEWS.d/next/Tests/2023-02-11-20-28-08.gh-issue-89792.S-Y5BZ.rst deleted file mode 100644 index 9de278919ef2..000000000000 --- a/Misc/NEWS.d/next/Tests/2023-02-11-20-28-08.gh-issue-89792.S-Y5BZ.rst +++ /dev/null @@ -1,4 +0,0 @@ -``test_tools`` now copies up to 10x less source data to a temporary directory -during the ``freeze`` test by ignoring git metadata and other artifacts. It -also limits its python build parallelism based on os.cpu_count instead of hard -coding it as 8 cores. diff --git a/Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst b/Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst deleted file mode 100644 index 94d160dd4127..000000000000 --- a/Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst +++ /dev/null @@ -1,2 +0,0 @@ -Adjust the error handling strategy in -``test_zoneinfo.TzPathTest.python_tzpath_context``. Patch by Paul Ganssle. diff --git a/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst b/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst deleted file mode 100644 index 48277367fc87..000000000000 --- a/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst +++ /dev/null @@ -1 +0,0 @@ -Improve test coverage on :mod:`pdb`. diff --git a/Misc/NEWS.d/next/Windows/2023-02-07-18-22-54.gh-issue-101614.NjVP0n.rst b/Misc/NEWS.d/next/Windows/2023-02-07-18-22-54.gh-issue-101614.NjVP0n.rst deleted file mode 100644 index 8ed0995d7892..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-02-07-18-22-54.gh-issue-101614.NjVP0n.rst +++ /dev/null @@ -1 +0,0 @@ -Correctly handle extensions built against debug binaries that reference ``python3_d.dll``. diff --git a/Misc/NEWS.d/next/Windows/2023-02-09-22-09-27.gh-issue-101759.zFlqSH.rst b/Misc/NEWS.d/next/Windows/2023-02-09-22-09-27.gh-issue-101759.zFlqSH.rst deleted file mode 100644 index 62bcac34397d..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-02-09-22-09-27.gh-issue-101759.zFlqSH.rst +++ /dev/null @@ -1 +0,0 @@ -Update Windows installer to SQLite 3.40.1. diff --git a/Misc/NEWS.d/next/Windows/2023-02-10-14-26-05.gh-issue-101763.RPaj7r.rst b/Misc/NEWS.d/next/Windows/2023-02-10-14-26-05.gh-issue-101763.RPaj7r.rst deleted file mode 100644 index e7e5a73afeb5..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-02-10-14-26-05.gh-issue-101763.RPaj7r.rst +++ /dev/null @@ -1 +0,0 @@ -Updates copy of libffi bundled with Windows installs to 3.4.4. diff --git a/Misc/NEWS.d/next/Windows/2023-02-13-16-32-50.gh-issue-101849.7lm_53.rst b/Misc/NEWS.d/next/Windows/2023-02-13-16-32-50.gh-issue-101849.7lm_53.rst deleted file mode 100644 index 861d4de9f9a6..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-02-13-16-32-50.gh-issue-101849.7lm_53.rst +++ /dev/null @@ -1 +0,0 @@ -Ensures installer will correctly upgrade existing ``py.exe`` launcher installs. diff --git a/Misc/NEWS.d/next/macOS/2023-02-09-22-07-17.gh-issue-101759.B0JP2H.rst b/Misc/NEWS.d/next/macOS/2023-02-09-22-07-17.gh-issue-101759.B0JP2H.rst deleted file mode 100644 index fc53d08bffc4..000000000000 --- a/Misc/NEWS.d/next/macOS/2023-02-09-22-07-17.gh-issue-101759.B0JP2H.rst +++ /dev/null @@ -1 +0,0 @@ -Update macOS installer to SQLite 3.40.1. diff --git a/Misc/NEWS.d/next/macOS/2023-04-04-13-37-28.gh-issue-103207.x0vvQp.rst b/Misc/NEWS.d/next/macOS/2023-04-04-13-37-28.gh-issue-103207.x0vvQp.rst deleted file mode 100644 index 3c176e3a6b53..000000000000 --- a/Misc/NEWS.d/next/macOS/2023-04-04-13-37-28.gh-issue-103207.x0vvQp.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add instructions to the macOS installer welcome display on how to workaround -the macOS 13 Ventura ?The installer encountered an error? failure. diff --git a/README.rst b/README.rst index 2cd94716f756..df59d4caf740 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.11.2 +This is Python version 3.11.3 ============================= .. image:: https://github.com/python/cpython/workflows/Tests/badge.svg From webhook-mailer at python.org Wed Apr 5 07:19:11 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Wed, 05 Apr 2023 11:19:11 -0000 Subject: [Python-checkins] gh-74690: typing: Call `_get_protocol_attrs` and `_callable_members_only` at protocol class creation time, not during `isinstance()` checks (#103160) Message-ID: https://github.com/python/cpython/commit/3246688918a428738b61c4adb5fbc6525eae96f9 commit: 3246688918a428738b61c4adb5fbc6525eae96f9 branch: main author: Alex Waygood committer: AlexWaygood date: 2023-04-05T12:19:03+01:00 summary: gh-74690: typing: Call `_get_protocol_attrs` and `_callable_members_only` at protocol class creation time, not during `isinstance()` checks (#103160) files: M Lib/typing.py diff --git a/Lib/typing.py b/Lib/typing.py index f50e9b0a93b0..b8420f619a1d 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1905,7 +1905,8 @@ class _TypingEllipsis: _TYPING_INTERNALS = frozenset({ '__parameters__', '__orig_bases__', '__orig_class__', - '_is_protocol', '_is_runtime_protocol' + '_is_protocol', '_is_runtime_protocol', '__protocol_attrs__', + '__callable_proto_members_only__', }) _SPECIAL_NAMES = frozenset({ @@ -1935,11 +1936,6 @@ def _get_protocol_attrs(cls): return attrs -def _is_callable_members_only(cls, protocol_attrs): - # PEP 544 prohibits using issubclass() with protocols that have non-method members. - return all(callable(getattr(cls, attr, None)) for attr in protocol_attrs) - - def _no_init_or_replace_init(self, *args, **kwargs): cls = type(self) @@ -2012,6 +2008,15 @@ def _lazy_load_getattr_static(): class _ProtocolMeta(ABCMeta): # This metaclass is really unfortunate and exists only because of # the lack of __instancehook__. + def __init__(cls, *args, **kwargs): + super().__init__(*args, **kwargs) + cls.__protocol_attrs__ = _get_protocol_attrs(cls) + # PEP 544 prohibits using issubclass() + # with protocols that have non-method members. + cls.__callable_proto_members_only__ = all( + callable(getattr(cls, attr, None)) for attr in cls.__protocol_attrs__ + ) + def __instancecheck__(cls, instance): # We need this method for situations where attributes are # assigned in __init__. @@ -2029,7 +2034,7 @@ def __instancecheck__(cls, instance): if is_protocol_cls: getattr_static = _lazy_load_getattr_static() - for attr in _get_protocol_attrs(cls): + for attr in cls.__protocol_attrs__: try: val = getattr_static(instance, attr) except AttributeError: @@ -2095,9 +2100,7 @@ def _proto_hook(other): raise TypeError("Instance and class checks can only be used with" " @runtime_checkable protocols") - protocol_attrs = _get_protocol_attrs(cls) - - if not _is_callable_members_only(cls, protocol_attrs): + if not cls.__callable_proto_members_only__ : if _allow_reckless_class_checks(): return NotImplemented raise TypeError("Protocols with non-method members" @@ -2107,7 +2110,7 @@ def _proto_hook(other): raise TypeError('issubclass() arg 1 must be a class') # Second, perform the actual structural compatibility check. - for attr in protocol_attrs: + for attr in cls.__protocol_attrs__: for base in other.__mro__: # Check if the members appears in the class dictionary... if attr in base.__dict__: From webhook-mailer at python.org Wed Apr 5 07:20:54 2023 From: webhook-mailer at python.org (pablogsal) Date: Wed, 05 Apr 2023 11:20:54 -0000 Subject: [Python-checkins] Python 3.10.11 Message-ID: https://github.com/python/cpython/commit/7d4cc5aa854fdea4d01a5b9c59e37c6e62f1103d commit: 7d4cc5aa854fdea4d01a5b9c59e37c6e62f1103d branch: 3.10 author: Pablo Galindo committer: pablogsal date: 2023-04-04T22:57:15+01:00 summary: Python 3.10.11 files: A Misc/NEWS.d/3.10.11.rst D Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-10-07-21-47.gh-issue-101765.MO5LlC.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-16-23-19-01.gh-issue-101967.Kqr1dz.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-24-17-59-39.gh-issue-102126.HTT8Vc.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst D Misc/NEWS.d/next/Documentation/2023-02-07-21-43-24.gh-issue-97725.cuY7Cd.rst D Misc/NEWS.d/next/Documentation/2023-02-19-10-33-01.gh-issue-85417.kYO8u3.rst D Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst D Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst D Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst D Misc/NEWS.d/next/Library/2022-09-05-12-17-34.gh-issue-88233.gff9qJ.rst D Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst D Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst D Misc/NEWS.d/next/Library/2023-02-10-16-02-29.gh-issue-101517.r7S2u8.rst D Misc/NEWS.d/next/Library/2023-02-11-13-23-29.gh-issue-97786.QjvQ1B.rst D Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst D Misc/NEWS.d/next/Library/2023-02-17-18-44-27.gh-issue-101997.A6_blD.rst D Misc/NEWS.d/next/Library/2023-02-17-20-24-15.gh-issue-101566.FjgWBt.rst D Misc/NEWS.d/next/Library/2023-02-21-07-15-41.gh-issue-101936.QVOxHH.rst D Misc/NEWS.d/next/Library/2023-02-21-10-05-33.gh-issue-101961.7e56jh.rst D Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst D Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst D Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst D Misc/NEWS.d/next/Security/2023-01-24-16-12-00.gh-issue-101283.9tqu39.rst D Misc/NEWS.d/next/Security/2023-02-08-22-03-04.gh-issue-101727.9P5eZz.rst D Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst D Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst D Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst D Misc/NEWS.d/next/Windows/2023-02-07-18-22-54.gh-issue-101614.NjVP0n.rst D Misc/NEWS.d/next/Windows/2023-02-09-22-09-27.gh-issue-101759.zFlqSH.rst D Misc/NEWS.d/next/macOS/2022-11-25-09-23-20.gh-issue-87235.SifjCD.rst D Misc/NEWS.d/next/macOS/2023-02-09-22-07-17.gh-issue-101759.B0JP2H.rst D Misc/NEWS.d/next/macOS/2023-04-04-13-37-28.gh-issue-103207.x0vvQp.rst M Include/patchlevel.h M Lib/pydoc_data/topics.py M README.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 353bf009dfca..394bdb4525f5 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -18,12 +18,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 10 -#define PY_MICRO_VERSION 10 +#define PY_MICRO_VERSION 11 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.10.10+" +#define PY_VERSION "3.10.11" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 1a888e4fb241..1637f382cf88 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Tue Feb 7 12:04:02 2023 +# Autogenerated by Sphinx on Tue Apr 4 22:56:51 2023 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' @@ -1136,10 +1136,11 @@ 'future, a\n' ' check may be added to prevent this.\n' '\n' - '* Nonempty *__slots__* does not work for classes derived ' - 'from\n' - ' ?variable-length? built-in types such as "int", ' - '"bytes" and "tuple".\n' + '* "TypeError" will be raised if nonempty *__slots__* are ' + 'defined for a\n' + ' class derived from a ""variable-length" built-in type" ' + 'such as\n' + ' "int", "bytes", and "tuple".\n' '\n' '* Any non-string *iterable* may be assigned to ' '*__slots__*.\n' @@ -2999,7 +3000,7 @@ 'AS\n' 'pattern binds the subject to the name on the right of the as ' 'keyword\n' - 'and succeeds. "capture_pattern" cannot be a a "_".\n' + 'and succeeds. "capture_pattern" cannot be a "_".\n' '\n' 'In simple terms "P as NAME" will match with "P", and on success ' 'it\n' @@ -4451,7 +4452,7 @@ 'objects and\n' ' implements an "__eq__()" method, it should not ' 'implement\n' - ' "__hash__()", since the implementation of hashable ' + ' "__hash__()", since the implementation of *hashable* ' 'collections\n' ' requires that a key?s hash value is immutable (if the ' 'object?s hash\n' @@ -4602,7 +4603,7 @@ 'scripts. For\n' 'example:\n' '\n' - ' python3 -m pdb myscript.py\n' + ' python -m pdb myscript.py\n' '\n' 'When invoked as a script, pdb will automatically enter ' 'post-mortem\n' @@ -4622,7 +4623,7 @@ '\n' 'New in version 3.7: "pdb.py" now accepts a "-m" option that ' 'execute\n' - 'modules similar to the way "python3 -m" does. As with a script, ' + 'modules similar to the way "python -m" does. As with a script, ' 'the\n' 'debugger will pause execution just before the first line of the\n' 'module.\n' @@ -4686,8 +4687,8 @@ 'object)\n' ' under debugger control. When "runeval()" returns, it returns ' 'the\n' - ' value of the expression. Otherwise this function is similar ' - 'to\n' + ' value of the *expression*. Otherwise this function is ' + 'similar to\n' ' "run()".\n' '\n' 'pdb.runcall(function, *args, **kwds)\n' @@ -4944,14 +4945,15 @@ 'ignore bpnumber [count]\n' '\n' ' Set the ignore count for the given breakpoint number. If ' - 'count is\n' - ' omitted, the ignore count is set to 0. A breakpoint becomes ' - 'active\n' - ' when the ignore count is zero. When non-zero, the count is\n' - ' decremented each time the breakpoint is reached and the ' - 'breakpoint\n' - ' is not disabled and any associated condition evaluates to ' - 'true.\n' + '*count*\n' + ' is omitted, the ignore count is set to 0. A breakpoint ' + 'becomes\n' + ' active when the ignore count is zero. When non-zero, the ' + '*count*\n' + ' is decremented each time the breakpoint is reached and the\n' + ' breakpoint is not disabled and any associated condition ' + 'evaluates\n' + ' to true.\n' '\n' 'condition bpnumber [condition]\n' '\n' @@ -5001,7 +5003,7 @@ ' breakpoint?which could have its own command list, leading to\n' ' ambiguities about which list to execute.\n' '\n' - ' If you use the ?silent? command in the command list, the ' + ' If you use the "silent" command in the command list, the ' 'usual\n' ' message about stopping at a breakpoint is not printed. This ' 'may be\n' @@ -5036,11 +5038,10 @@ 'number\n' ' greater than the current one is reached.\n' '\n' - ' With a line number, continue execution until a line with a ' - 'number\n' - ' greater or equal to that is reached. In both cases, also ' - 'stop when\n' - ' the current frame returns.\n' + ' With *lineno*, continue execution until a line with a number\n' + ' greater or equal to *lineno* is reached. In both cases, also ' + 'stop\n' + ' when the current frame returns.\n' '\n' ' Changed in version 3.2: Allow giving an explicit line ' 'number.\n' @@ -5104,9 +5105,8 @@ '\n' 'p expression\n' '\n' - ' Evaluate the *expression* in the current context and print ' - 'its\n' - ' value.\n' + ' Evaluate *expression* in the current context and print its ' + 'value.\n' '\n' ' Note:\n' '\n' @@ -5116,26 +5116,26 @@ '\n' 'pp expression\n' '\n' - ' Like the "p" command, except the value of the expression is ' + ' Like the "p" command, except the value of *expression* is ' 'pretty-\n' ' printed using the "pprint" module.\n' '\n' 'whatis expression\n' '\n' - ' Print the type of the *expression*.\n' + ' Print the type of *expression*.\n' '\n' 'source expression\n' '\n' - ' Try to get source code for the given object and display it.\n' + ' Try to get source code of *expression* and display it.\n' '\n' ' New in version 3.2.\n' '\n' 'display [expression]\n' '\n' - ' Display the value of the expression if it changed, each time\n' + ' Display the value of *expression* if it changed, each time\n' ' execution stops in the current frame.\n' '\n' - ' Without expression, list all display expressions for the ' + ' Without *expression*, list all display expressions for the ' 'current\n' ' frame.\n' '\n' @@ -5143,10 +5143,10 @@ '\n' 'undisplay [expression]\n' '\n' - ' Do not display the expression any more in the current frame.\n' - ' Without expression, clear all display expressions for the ' - 'current\n' - ' frame.\n' + ' Do not display *expression* anymore in the current frame. ' + 'Without\n' + ' *expression*, clear all display expressions for the current ' + 'frame.\n' '\n' ' New in version 3.2.\n' '\n' @@ -5162,16 +5162,16 @@ '\n' 'alias [name [command]]\n' '\n' - ' Create an alias called *name* that executes *command*. The ' - 'command\n' - ' must *not* be enclosed in quotes. Replaceable parameters can ' - 'be\n' - ' indicated by "%1", "%2", and so on, while "%*" is replaced by ' - 'all\n' - ' the parameters. If no command is given, the current alias ' - 'for\n' - ' *name* is shown. If no arguments are given, all aliases are ' - 'listed.\n' + ' Create an alias called *name* that executes *command*. The\n' + ' *command* must *not* be enclosed in quotes. Replaceable ' + 'parameters\n' + ' can be indicated by "%1", "%2", and so on, while "%*" is ' + 'replaced\n' + ' by all the parameters. If *command* is omitted, the current ' + 'alias\n' + ' for *name* is shown. If no arguments are given, all aliases ' + 'are\n' + ' listed.\n' '\n' ' Aliases may be nested and can contain anything that can be ' 'legally\n' @@ -5190,14 +5190,14 @@ ' in the ".pdbrc" file):\n' '\n' ' # Print instance variables (usage "pi classInst")\n' - ' alias pi for k in %1.__dict__.keys(): ' - 'print("%1.",k,"=",%1.__dict__[k])\n' + ' alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = ' + '{%1.__dict__[k]}")\n' ' # Print instance variables in self\n' ' alias ps pi self\n' '\n' 'unalias name\n' '\n' - ' Delete the specified alias.\n' + ' Delete the specified alias *name*.\n' '\n' '! statement\n' '\n' @@ -5217,12 +5217,13 @@ 'run [args ...]\n' 'restart [args ...]\n' '\n' - ' Restart the debugged Python program. If an argument is ' - 'supplied,\n' - ' it is split with "shlex" and the result is used as the new\n' - ' "sys.argv". History, breakpoints, actions and debugger ' - 'options are\n' - ' preserved. "restart" is an alias for "run".\n' + ' Restart the debugged Python program. If *args* is supplied, ' + 'it is\n' + ' split with "shlex" and the result is used as the new ' + '"sys.argv".\n' + ' History, breakpoints, actions and debugger options are ' + 'preserved.\n' + ' "restart" is an alias for "run".\n' '\n' 'q(uit)\n' '\n' @@ -5231,11 +5232,11 @@ '\n' 'debug code\n' '\n' - ' Enter a recursive debugger that steps through the code ' - 'argument\n' - ' (which is an arbitrary expression or statement to be executed ' - 'in\n' - ' the current environment).\n' + ' Enter a recursive debugger that steps through *code* (which ' + 'is an\n' + ' arbitrary expression or statement to be executed in the ' + 'current\n' + ' environment).\n' '\n' 'retval\n' '\n' @@ -9347,7 +9348,7 @@ ' hashable collections. If a class defines mutable objects ' 'and\n' ' implements an "__eq__()" method, it should not implement\n' - ' "__hash__()", since the implementation of hashable ' + ' "__hash__()", since the implementation of *hashable* ' 'collections\n' ' requires that a key?s hash value is immutable (if the ' 'object?s hash\n' @@ -9885,10 +9886,11 @@ 'future, a\n' ' check may be added to prevent this.\n' '\n' - '* Nonempty *__slots__* does not work for classes derived ' - 'from\n' - ' ?variable-length? built-in types such as "int", "bytes" ' - 'and "tuple".\n' + '* "TypeError" will be raised if nonempty *__slots__* are ' + 'defined for a\n' + ' class derived from a ""variable-length" built-in type" ' + 'such as\n' + ' "int", "bytes", and "tuple".\n' '\n' '* Any non-string *iterable* may be assigned to *__slots__*.\n' '\n' @@ -14160,7 +14162,7 @@ ' New in version 3.10.\n' '\n' 'Keys views are set-like since their entries are unique and ' - 'hashable.\n' + '*hashable*.\n' 'If all values are hashable, so that "(key, value)" pairs are ' 'unique\n' 'and hashable, then the items view is also set-like. (Values ' diff --git a/Misc/NEWS.d/3.10.11.rst b/Misc/NEWS.d/3.10.11.rst new file mode 100644 index 000000000000..caf6c046b330 --- /dev/null +++ b/Misc/NEWS.d/3.10.11.rst @@ -0,0 +1,359 @@ +.. date: 2023-02-08-22-03-04 +.. gh-issue: 101727 +.. nonce: 9P5eZz +.. release date: 2023-04-04 +.. section: Security + +Updated the OpenSSL version used in Windows and macOS binary release builds +to 1.1.1t to address CVE-2023-0286, CVE-2022-4303, and CVE-2022-4303 per +`the OpenSSL 2023-02-07 security advisory +`_. + +.. + +.. date: 2023-01-24-16-12-00 +.. gh-issue: 101283 +.. nonce: 9tqu39 +.. section: Security + +:class:`subprocess.Popen` now uses a safer approach to find ``cmd.exe`` when +launching with ``shell=True``. Patch by Eryk Sun, based on a patch by Oleg +Iarygin. + +.. + +.. date: 2023-03-06-13-05-33 +.. gh-issue: 102416 +.. nonce: dz6K5f +.. section: Core and Builtins + +Do not memoize incorrectly automatically generated loop rules in the parser. +Patch by Pablo Galindo. + +.. + +.. date: 2023-03-04-20-56-12 +.. gh-issue: 102356 +.. nonce: 07KvUd +.. section: Core and Builtins + +Fix a bug that caused a crash when deallocating deeply nested filter +objects. Patch by Marta G?mez Mac?as. + +.. + +.. date: 2023-03-04-06-48-34 +.. gh-issue: 102397 +.. nonce: ACJaOf +.. section: Core and Builtins + +Fix segfault from race condition in signal handling during garbage +collection. Patch by Kumar Aditya. + +.. + +.. date: 2023-02-24-17-59-39 +.. gh-issue: 102126 +.. nonce: HTT8Vc +.. section: Core and Builtins + +Fix deadlock at shutdown when clearing thread states if any finalizer tries +to acquire the runtime head lock. Patch by Kumar Aditya. + +.. + +.. date: 2023-02-21-23-42-39 +.. gh-issue: 102027 +.. nonce: fQARG0 +.. section: Core and Builtins + +Fix SSE2 and SSE3 detection in ``_blake2`` internal module. Patch by Max +Bachmann. + +.. + +.. date: 2023-02-16-23-19-01 +.. gh-issue: 101967 +.. nonce: Kqr1dz +.. section: Core and Builtins + +Fix possible segfault in ``positional_only_passed_as_keyword`` function, +when new list created. + +.. + +.. date: 2023-02-10-07-21-47 +.. gh-issue: 101765 +.. nonce: MO5LlC +.. section: Core and Builtins + +Fix SystemError / segmentation fault in iter ``__reduce__`` when internal +access of ``builtins.__dict__`` keys mutates the iter object. + +.. + +.. date: 2023-03-23-13-34-33 +.. gh-issue: 102947 +.. nonce: cTwcpU +.. section: Library + +Improve traceback when :func:`dataclasses.fields` is called on a +non-dataclass. Patch by Alex Waygood + +.. + +.. date: 2023-02-28-09-52-25 +.. gh-issue: 101979 +.. nonce: or3hXV +.. section: Library + +Fix a bug where parentheses in the ``metavar`` argument to +:meth:`argparse.ArgumentParser.add_argument` were dropped. Patch by Yeojin +Kim. + +.. + +.. date: 2023-02-23-15-06-01 +.. gh-issue: 102179 +.. nonce: P6KQ4c +.. section: Library + +Fix :func:`os.dup2` error message for negative fds. + +.. + +.. date: 2023-02-21-10-05-33 +.. gh-issue: 101961 +.. nonce: 7e56jh +.. section: Library + +For the binary mode, :func:`fileinput.hookcompressed` doesn't set the +``encoding`` value even if the value is ``None``. Patch by Gihwan Kim. + +.. + +.. date: 2023-02-21-07-15-41 +.. gh-issue: 101936 +.. nonce: QVOxHH +.. section: Library + +The default value of ``fp`` becomes :class:`io.BytesIO` if +:exc:`~urllib.error.HTTPError` is initialized without a designated ``fp`` +parameter. Patch by Long Vo. + +.. + +.. date: 2023-02-17-20-24-15 +.. gh-issue: 101566 +.. nonce: FjgWBt +.. section: Library + +In zipfile, apply fix for extractall on the underlying zipfile after being +wrapped in ``Path``. + +.. + +.. date: 2023-02-17-18-44-27 +.. gh-issue: 101997 +.. nonce: A6_blD +.. section: Library + +Upgrade pip wheel bundled with ensurepip (pip 23.0.1) + +.. + +.. date: 2023-02-14-09-08-48 +.. gh-issue: 101892 +.. nonce: FMos8l +.. section: Library + +Callable iterators no longer raise :class:`SystemError` when the callable +object exhausts the iterator but forgets to either return a sentinel value +or raise :class:`StopIteration`. + +.. + +.. date: 2023-02-11-13-23-29 +.. gh-issue: 97786 +.. nonce: QjvQ1B +.. section: Library + +Fix potential undefined behaviour in corner cases of floating-point-to-time +conversions. + +.. + +.. date: 2023-02-10-16-02-29 +.. gh-issue: 101517 +.. nonce: r7S2u8 +.. section: Library + +Fixed bug where :mod:`bdb` looks up the source line with :mod:`linecache` +with a ``lineno=None``, which causes it to fail with an unhandled exception. + +.. + +.. date: 2023-02-09-19-40-41 +.. gh-issue: 101673 +.. nonce: mX-Ppq +.. section: Library + +Fix a :mod:`pdb` bug where ``ll`` clears the changes to local variables. + +.. + +.. date: 2022-09-19-08-12-58 +.. gh-issue: 96931 +.. nonce: x0WQhh +.. section: Library + +Fix incorrect results from :meth:`ssl.SSLSocket.shared_ciphers` + +.. + +.. date: 2022-09-05-12-17-34 +.. gh-issue: 88233 +.. nonce: gff9qJ +.. section: Library + +Correctly preserve "extra" fields in ``zipfile`` regardless of their +ordering relative to a zip64 "extra." + +.. + +.. date: 2022-07-30-23-01-43 +.. gh-issue: 95495 +.. nonce: RA-q1d +.. section: Library + +When built against OpenSSL 3.0, the :mod:`ssl` module had a bug where it +reported unauthenticated EOFs (i.e. without close_notify) as a clean +TLS-level EOF. It now raises :exc:`~ssl.SSLEOFError`, matching the behavior +in previous versions of OpenSSL. The :attr:`~ssl.SSLContext.options` +attribute on :class:`~ssl.SSLContext` also no longer includes +:data:`~ssl.OP_IGNORE_UNEXPECTED_EOF` by default. This option may be set to +specify the previous OpenSSL 3.0 behavior. + +.. + +.. date: 2022-06-30-21-28-41 +.. gh-issue: 94440 +.. nonce: LtgX0d +.. section: Library + +Fix a :mod:`concurrent.futures.process` bug where ``ProcessPoolExecutor`` +shutdown could hang after a future has been quickly submitted and canceled. + +.. + +.. date: 2023-03-29-14-51-39 +.. gh-issue: 103112 +.. nonce: XgGSEO +.. section: Documentation + +Add docstring to :meth:`http.client.HTTPResponse.read` to fix ``pydoc`` +output. + +.. + +.. date: 2023-02-19-10-33-01 +.. gh-issue: 85417 +.. nonce: kYO8u3 +.. section: Documentation + +Update :mod:`cmath` documentation to clarify behaviour on branch cuts. + +.. + +.. date: 2023-02-07-21-43-24 +.. gh-issue: 97725 +.. nonce: cuY7Cd +.. section: Documentation + +Fix :meth:`asyncio.Task.print_stack` description for ``file=None``. Patch by +Oleg Iarygin. + +.. + +.. date: 2023-03-23-23-25-18 +.. gh-issue: 102980 +.. nonce: Zps4QF +.. section: Tests + +Improve test coverage on :mod:`pdb`. + +.. + +.. date: 2023-03-08-13-54-20 +.. gh-issue: 102537 +.. nonce: Vfplpb +.. section: Tests + +Adjust the error handling strategy in +``test_zoneinfo.TzPathTest.python_tzpath_context``. Patch by Paul Ganssle. + +.. + +.. date: 2023-01-27-18-10-40 +.. gh-issue: 101377 +.. nonce: IJGpqh +.. section: Tests + +Improved test_locale_calendar_formatweekday of calendar. + +.. + +.. date: 2023-03-15-02-03-39 +.. gh-issue: 102711 +.. nonce: zTkjts +.. section: Build + +Fix ``-Wstrict-prototypes`` compiler warnings. + +.. + +.. date: 2023-02-09-22-09-27 +.. gh-issue: 101759 +.. nonce: zFlqSH +.. section: Windows + +Update Windows installer to SQLite 3.40.1. + +.. + +.. date: 2023-02-07-18-22-54 +.. gh-issue: 101614 +.. nonce: NjVP0n +.. section: Windows + +Correctly handle extensions built against debug binaries that reference +``python3_d.dll``. + +.. + +.. date: 2023-04-04-13-37-28 +.. gh-issue: 103207 +.. nonce: x0vvQp +.. section: macOS + +Add instructions to the macOS installer welcome display on how to workaround +the macOS 13 Ventura ?The installer encountered an error? failure. + +.. + +.. date: 2023-02-09-22-07-17 +.. gh-issue: 101759 +.. nonce: B0JP2H +.. section: macOS + +Update macOS installer to SQLite 3.40.1. + +.. + +.. date: 2022-11-25-09-23-20 +.. gh-issue: 87235 +.. nonce: SifjCD +.. section: macOS + +On macOS ``python3 /dev/fd/9 9`_. diff --git a/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst b/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst deleted file mode 100644 index a9c19ce060e3..000000000000 --- a/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst +++ /dev/null @@ -1 +0,0 @@ -Improved test_locale_calendar_formatweekday of calendar. diff --git a/Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst b/Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst deleted file mode 100644 index 94d160dd4127..000000000000 --- a/Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst +++ /dev/null @@ -1,2 +0,0 @@ -Adjust the error handling strategy in -``test_zoneinfo.TzPathTest.python_tzpath_context``. Patch by Paul Ganssle. diff --git a/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst b/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst deleted file mode 100644 index 48277367fc87..000000000000 --- a/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst +++ /dev/null @@ -1 +0,0 @@ -Improve test coverage on :mod:`pdb`. diff --git a/Misc/NEWS.d/next/Windows/2023-02-07-18-22-54.gh-issue-101614.NjVP0n.rst b/Misc/NEWS.d/next/Windows/2023-02-07-18-22-54.gh-issue-101614.NjVP0n.rst deleted file mode 100644 index 8ed0995d7892..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-02-07-18-22-54.gh-issue-101614.NjVP0n.rst +++ /dev/null @@ -1 +0,0 @@ -Correctly handle extensions built against debug binaries that reference ``python3_d.dll``. diff --git a/Misc/NEWS.d/next/Windows/2023-02-09-22-09-27.gh-issue-101759.zFlqSH.rst b/Misc/NEWS.d/next/Windows/2023-02-09-22-09-27.gh-issue-101759.zFlqSH.rst deleted file mode 100644 index 62bcac34397d..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-02-09-22-09-27.gh-issue-101759.zFlqSH.rst +++ /dev/null @@ -1 +0,0 @@ -Update Windows installer to SQLite 3.40.1. diff --git a/Misc/NEWS.d/next/macOS/2022-11-25-09-23-20.gh-issue-87235.SifjCD.rst b/Misc/NEWS.d/next/macOS/2022-11-25-09-23-20.gh-issue-87235.SifjCD.rst deleted file mode 100644 index 3111e4975e87..000000000000 --- a/Misc/NEWS.d/next/macOS/2022-11-25-09-23-20.gh-issue-87235.SifjCD.rst +++ /dev/null @@ -1 +0,0 @@ -On macOS ``python3 /dev/fd/9 9 https://github.com/python/cpython/commit/8693ec214c2fa6cc1ea2e71f308735b6d9ea55f1 commit: 8693ec214c2fa6cc1ea2e71f308735b6d9ea55f1 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-05T04:24:43-07:00 summary: gh-81762: Clarify and simplify description of print's flush param (GH-103264) (cherry picked from commit c396b6ddf3da784349bac9ebf7f28c55bde016ea) Co-authored-by: C.A.M. Gerlach files: M Doc/library/functions.rst diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 4e4c49ce3a6b..7b69855caaf2 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1423,8 +1423,9 @@ are always available. They are listed here in alphabetical order. arguments are converted to text strings, :func:`print` cannot be used with binary mode file objects. For these, use ``file.write(...)`` instead. - Whether the output is buffered is usually determined by *file*, but if the - *flush* keyword argument is true, the stream is forcibly flushed. + Output buffering is usually determined by *file*. + However, if *flush* is true, the stream is forcibly flushed. + .. versionchanged:: 3.3 Added the *flush* keyword argument. From webhook-mailer at python.org Wed Apr 5 07:43:47 2023 From: webhook-mailer at python.org (iritkatriel) Date: Wed, 05 Apr 2023 11:43:47 -0000 Subject: [Python-checkins] gh-100408: Fix a traceback in multiprocessing example (#100409) Message-ID: https://github.com/python/cpython/commit/a28d4edb23b7150942f1eceb9e97c6f53aa4de42 commit: a28d4edb23b7150942f1eceb9e97c6f53aa4de42 branch: main author: Serhiy Storchaka committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-04-05T12:43:26+01:00 summary: gh-100408: Fix a traceback in multiprocessing example (#100409) files: M Doc/library/multiprocessing.rst diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 0ec47bb956a9..8454296b815b 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -460,16 +460,16 @@ process which created it. ... return x*x ... >>> with p: - ... p.map(f, [1,2,3]) + ... p.map(f, [1,2,3]) Process PoolWorker-1: Process PoolWorker-2: Process PoolWorker-3: Traceback (most recent call last): Traceback (most recent call last): Traceback (most recent call last): - AttributeError: 'module' object has no attribute 'f' - AttributeError: 'module' object has no attribute 'f' - AttributeError: 'module' object has no attribute 'f' + AttributeError: Can't get attribute 'f' on )> + AttributeError: Can't get attribute 'f' on )> + AttributeError: Can't get attribute 'f' on )> (If you try this it will actually output three full tracebacks interleaved in a semi-random fashion, and then you may have to From webhook-mailer at python.org Wed Apr 5 07:49:15 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Apr 2023 11:49:15 -0000 Subject: [Python-checkins] gh-81762: Clarify and simplify description of print's flush param (GH-103264) Message-ID: https://github.com/python/cpython/commit/9357fc9b89e808bf4731473e2e905a218b96ebf8 commit: 9357fc9b89e808bf4731473e2e905a218b96ebf8 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-05T04:49:08-07:00 summary: gh-81762: Clarify and simplify description of print's flush param (GH-103264) (cherry picked from commit c396b6ddf3da784349bac9ebf7f28c55bde016ea) Co-authored-by: C.A.M. Gerlach files: M Doc/library/functions.rst diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 22972c038750..2ce3860440be 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1443,8 +1443,9 @@ are always available. They are listed here in alphabetical order. arguments are converted to text strings, :func:`print` cannot be used with binary mode file objects. For these, use ``file.write(...)`` instead. - Whether the output is buffered is usually determined by *file*, but if the - *flush* keyword argument is true, the stream is forcibly flushed. + Output buffering is usually determined by *file*. + However, if *flush* is true, the stream is forcibly flushed. + .. versionchanged:: 3.3 Added the *flush* keyword argument. From webhook-mailer at python.org Wed Apr 5 07:54:56 2023 From: webhook-mailer at python.org (corona10) Date: Wed, 05 Apr 2023 11:54:56 -0000 Subject: [Python-checkins] gh-86094: Add support for Unicode Path Extra Field in ZipFile (gh-102566) Message-ID: https://github.com/python/cpython/commit/8f70b16e3397ad32757ddbabd5180cbef0036a4b commit: 8f70b16e3397ad32757ddbabd5180cbef0036a4b branch: main author: Yeojin Kim committer: corona10 date: 2023-04-05T20:54:48+09:00 summary: gh-86094: Add support for Unicode Path Extra Field in ZipFile (gh-102566) files: A Misc/NEWS.d/next/Documentation/2023-03-10-04-59-35.gh-issue-86094.zOYdy8.rst M Lib/test/test_zipfile/test_core.py M Lib/zipfile/__init__.py M Misc/ACKS diff --git a/Lib/test/test_zipfile/test_core.py b/Lib/test/test_zipfile/test_core.py index e23f5c2a8556..73c6b0185a1a 100644 --- a/Lib/test/test_zipfile/test_core.py +++ b/Lib/test/test_zipfile/test_core.py @@ -1616,6 +1616,33 @@ def test_write_unicode_filenames(self): self.assertEqual(zf.filelist[0].filename, "foo.txt") self.assertEqual(zf.filelist[1].filename, "\xf6.txt") + @requires_zlib() + def test_read_zipfile_containing_unicode_path_extra_field(self): + with zipfile.ZipFile(TESTFN, mode='w') as zf: + # create a file with a non-ASCII name + filename = '??.txt' + filename_encoded = filename.encode('utf-8') + + # create a ZipInfo object with Unicode path extra field + zip_info = zipfile.ZipInfo(filename) + + tag_for_unicode_path = b'\x75\x70' + version_of_unicode_path = b'\x01' + + import zlib + filename_crc = struct.pack('= 0: + filename = filename[0:null_byte] + # This is used to ensure paths in generated ZIP files always use + # forward slashes as the directory separator, as required by the + # ZIP format specification. + if os.sep != "/" and os.sep in filename: + filename = filename.replace(os.sep, "/") + return filename + class ZipInfo (object): """Class with attributes describing each file in the ZIP archive.""" @@ -368,16 +384,9 @@ class ZipInfo (object): def __init__(self, filename="NoName", date_time=(1980,1,1,0,0,0)): self.orig_filename = filename # Original file name in archive - # Terminate the file name at the first null byte. Null bytes in file - # names are used as tricks by viruses in archives. - null_byte = filename.find(chr(0)) - if null_byte >= 0: - filename = filename[0:null_byte] - # This is used to ensure paths in generated ZIP files always use - # forward slashes as the directory separator, as required by the - # ZIP format specification. - if os.sep != "/" and os.sep in filename: - filename = filename.replace(os.sep, "/") + # Terminate the file name at the first null byte and + # ensure paths always use forward slashes as the directory separator. + filename = _sanitize_filename(filename) self.filename = filename # Normalized file name self.date_time = date_time # year, month, day, hour, min, sec @@ -482,7 +491,7 @@ def _encodeFilenameFlags(self): except UnicodeEncodeError: return self.filename.encode('utf-8'), self.flag_bits | _MASK_UTF_FILENAME - def _decodeExtra(self): + def _decodeExtra(self, filename_crc): # Try to decode the extra field. extra = self.extra unpack = struct.unpack @@ -508,6 +517,21 @@ def _decodeExtra(self): except struct.error: raise BadZipFile(f"Corrupt zip64 extra field. " f"{field} not found.") from None + elif tp == 0x7075: + data = extra[4:ln+4] + # Unicode Path Extra Field + try: + up_version, up_name_crc = unpack(' 2: print(centdir) filename = fp.read(centdir[_CD_FILENAME_LENGTH]) + orig_filename_crc = crc32(filename) flags = centdir[_CD_FLAG_BITS] if flags & _MASK_UTF_FILENAME: # UTF-8 file names extension @@ -1432,8 +1457,7 @@ def _RealGetContents(self): x._raw_time = t x.date_time = ( (d>>9)+1980, (d>>5)&0xF, d&0x1F, t>>11, (t>>5)&0x3F, (t&0x1F) * 2 ) - - x._decodeExtra() + x._decodeExtra(orig_filename_crc) x.header_offset = x.header_offset + concat self.filelist.append(x) self.NameToInfo[x.filename] = x diff --git a/Misc/ACKS b/Misc/ACKS index 929e06a87cb7..49f3692dfd6b 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -627,6 +627,7 @@ Julian Gindi Yannick Gingras Neil Girdhar Matt Giuca +Andrea Giudiceandrea Franz Glasner Wim Glenn Michael Goderbauer diff --git a/Misc/NEWS.d/next/Documentation/2023-03-10-04-59-35.gh-issue-86094.zOYdy8.rst b/Misc/NEWS.d/next/Documentation/2023-03-10-04-59-35.gh-issue-86094.zOYdy8.rst new file mode 100644 index 000000000000..39461f3f84c9 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-03-10-04-59-35.gh-issue-86094.zOYdy8.rst @@ -0,0 +1,2 @@ +Add support for Unicode Path Extra Field in ZipFile. Patch by Yeojin Kim +and Andrea Giudiceandrea From webhook-mailer at python.org Wed Apr 5 10:52:46 2023 From: webhook-mailer at python.org (iritkatriel) Date: Wed, 05 Apr 2023 14:52:46 -0000 Subject: [Python-checkins] gh-89058: remove skip from test_no_hang_on_context_chain_cycle2 (#102903) Message-ID: https://github.com/python/cpython/commit/5e7c468fc4ceb801c30844b794e04a2ac6a35743 commit: 5e7c468fc4ceb801c30844b794e04a2ac6a35743 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-04-05T15:52:38+01:00 summary: gh-89058: remove skip from test_no_hang_on_context_chain_cycle2 (#102903) files: M Lib/test/test_exceptions.py diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 284f26be7177..74a5884264d5 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -1135,7 +1135,6 @@ def cycle(): self.assertIsInstance(exc.__context__, ValueError) self.assertIs(exc.__context__.__context__, exc.__context__) - @unittest.skip("See issue 44895") def test_no_hang_on_context_chain_cycle2(self): # See issue 25782. Cycle at head of context chain. From webhook-mailer at python.org Wed Apr 5 10:54:51 2023 From: webhook-mailer at python.org (vstinner) Date: Wed, 05 Apr 2023 14:54:51 -0000 Subject: [Python-checkins] gh-102899: Fix doc link for getting filesystem error handler (#102901) Message-ID: https://github.com/python/cpython/commit/fdd0fff277a55c010a4da0a7af0e986e38560545 commit: fdd0fff277a55c010a4da0a7af0e986e38560545 branch: main author: Olivier Gayot committer: vstinner date: 2023-04-05T16:54:43+02:00 summary: gh-102899: Fix doc link for getting filesystem error handler (#102901) files: M Doc/library/sys.rst diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index b3b9b5e74ac0..00721efd1cf6 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -697,7 +697,7 @@ always available. the encoding used with the :term:`filesystem error handler ` to convert between Unicode filenames and bytes filenames. The filesystem error handler is returned from - :func:`getfilesystemencoding`. + :func:`getfilesystemencodeerrors`. For best compatibility, str should be used for filenames in all cases, although representing filenames as bytes is also supported. Functions From webhook-mailer at python.org Wed Apr 5 11:03:53 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Apr 2023 15:03:53 -0000 Subject: [Python-checkins] gh-102899: Fix doc link for getting filesystem error handler (GH-102901) Message-ID: https://github.com/python/cpython/commit/18d825be8c74f41e62466638c60d2b663dea03b6 commit: 18d825be8c74f41e62466638c60d2b663dea03b6 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-05T08:03:45-07:00 summary: gh-102899: Fix doc link for getting filesystem error handler (GH-102901) (cherry picked from commit fdd0fff277a55c010a4da0a7af0e986e38560545) Co-authored-by: Olivier Gayot files: M Doc/library/sys.rst diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index cf20d33ab6e8..5a859b68ef80 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -651,7 +651,7 @@ always available. the encoding used with the :term:`filesystem error handler ` to convert between Unicode filenames and bytes filenames. The filesystem error handler is returned from - :func:`getfilesystemencoding`. + :func:`getfilesystemencodeerrors`. For best compatibility, str should be used for filenames in all cases, although representing filenames as bytes is also supported. Functions From webhook-mailer at python.org Wed Apr 5 11:03:56 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Apr 2023 15:03:56 -0000 Subject: [Python-checkins] gh-102899: Fix doc link for getting filesystem error handler (GH-102901) Message-ID: https://github.com/python/cpython/commit/09fb27fa51aeafbc61a51c5e748c97b18d907c8b commit: 09fb27fa51aeafbc61a51c5e748c97b18d907c8b branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-05T08:03:47-07:00 summary: gh-102899: Fix doc link for getting filesystem error handler (GH-102901) (cherry picked from commit fdd0fff277a55c010a4da0a7af0e986e38560545) Co-authored-by: Olivier Gayot files: M Doc/library/sys.rst diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 79df611a2724..3d1506f553ad 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -697,7 +697,7 @@ always available. the encoding used with the :term:`filesystem error handler ` to convert between Unicode filenames and bytes filenames. The filesystem error handler is returned from - :func:`getfilesystemencoding`. + :func:`getfilesystemencodeerrors`. For best compatibility, str should be used for filenames in all cases, although representing filenames as bytes is also supported. Functions From webhook-mailer at python.org Wed Apr 5 11:09:28 2023 From: webhook-mailer at python.org (vstinner) Date: Wed, 05 Apr 2023 15:09:28 -0000 Subject: [Python-checkins] gh-99069: Consolidate checks for static_assert (#94766) Message-ID: https://github.com/python/cpython/commit/96e1901a59ed3bb6188743d60395666969a3ba42 commit: 96e1901a59ed3bb6188743d60395666969a3ba42 branch: main author: Joshua Root committer: vstinner date: 2023-04-05T17:09:19+02:00 summary: gh-99069: Consolidate checks for static_assert (#94766) Several platforms don't define the static_assert macro despite having compiler support for the _Static_assert keyword. The macro needs to be defined since it is used unconditionally in the Python code. So it should always be safe to define it if undefined and not in C++11 (or later) mode. Hence, remove the checks for particular platforms or libc versions, and just define static_assert anytime it needs to be defined but isn't. That way, all platforms that need the fix will get it, regardless of whether someone specifically thought of them. Also document that certain macOS versions are among the platforms that need this. The C2x draft (currently expected to become C23) makes static_assert a keyword to match C++. So only define the macro for up to C17. Co-authored-by: Victor Stinner files: A Misc/NEWS.d/next/Build/2023-02-11-05-31-05.gh-issue-99069.X4LDvY.rst M Include/pymacro.h diff --git a/Include/pymacro.h b/Include/pymacro.h index e37cda44c5ebf..342d2a7b844ad 100644 --- a/Include/pymacro.h +++ b/Include/pymacro.h @@ -3,20 +3,23 @@ // gh-91782: On FreeBSD 12, if the _POSIX_C_SOURCE and _XOPEN_SOURCE macros are // defined, disables C11 support and does not define -// the static_assert() macro. Define the static_assert() macro in Python until -// suports C11: +// the static_assert() macro. // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=255290 -#if defined(__FreeBSD__) && !defined(static_assert) -# define static_assert _Static_assert -#endif - -// static_assert is defined in glibc from version 2.16. Before it requires -// compiler support (gcc >= 4.6) and is called _Static_assert. -// In C++ 11 static_assert is a keyword, redefining is undefined behaviour. -#if (defined(__GLIBC__) \ - && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 16)) \ - && !(defined(__cplusplus) && __cplusplus >= 201103L) \ - && !defined(static_assert)) +// +// macOS <= 10.10 doesn't define static_assert in assert.h at all despite +// having C11 compiler support. +// +// static_assert is defined in glibc from version 2.16. Compiler support for +// the C11 _Static_assert keyword is in gcc >= 4.6. +// +// MSVC makes static_assert a keyword in C11-17, contrary to the standards. +// +// In C++11 and C2x, static_assert is a keyword, redefining is undefined +// behaviour. So only define if building as C (if __STDC_VERSION__ is defined), +// not C++, and only for C11-17. +#if !defined(static_assert) && (defined(__GNUC__) || defined(__clang__)) \ + && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \ + && __STDC_VERSION__ <= 201710L # define static_assert _Static_assert #endif diff --git a/Misc/NEWS.d/next/Build/2023-02-11-05-31-05.gh-issue-99069.X4LDvY.rst b/Misc/NEWS.d/next/Build/2023-02-11-05-31-05.gh-issue-99069.X4LDvY.rst new file mode 100644 index 0000000000000..ae9b4d59ca8ce --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-02-11-05-31-05.gh-issue-99069.X4LDvY.rst @@ -0,0 +1 @@ +Extended workaround defining ``static_assert`` when missing from the libc headers to all clang and gcc builds. In particular, this fixes building on macOS <= 10.10. From webhook-mailer at python.org Wed Apr 5 11:44:20 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 05 Apr 2023 15:44:20 -0000 Subject: [Python-checkins] gh-99069: Consolidate checks for static_assert (GH-94766) Message-ID: https://github.com/python/cpython/commit/851e74441e5264bf2bd1383d053de2196e157140 commit: 851e74441e5264bf2bd1383d053de2196e157140 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-05T08:44:13-07:00 summary: gh-99069: Consolidate checks for static_assert (GH-94766) Several platforms don't define the static_assert macro despite having compiler support for the _Static_assert keyword. The macro needs to be defined since it is used unconditionally in the Python code. So it should always be safe to define it if undefined and not in C++11 (or later) mode. Hence, remove the checks for particular platforms or libc versions, and just define static_assert anytime it needs to be defined but isn't. That way, all platforms that need the fix will get it, regardless of whether someone specifically thought of them. Also document that certain macOS versions are among the platforms that need this. The C2x draft (currently expected to become C23) makes static_assert a keyword to match C++. So only define the macro for up to C17. (cherry picked from commit 96e1901a59ed3bb6188743d60395666969a3ba42) Co-authored-by: Joshua Root Co-authored-by: Victor Stinner files: A Misc/NEWS.d/next/Build/2023-02-11-05-31-05.gh-issue-99069.X4LDvY.rst M Include/pymacro.h diff --git a/Include/pymacro.h b/Include/pymacro.h index 90ad8f078444..5840966b5f8d 100644 --- a/Include/pymacro.h +++ b/Include/pymacro.h @@ -3,20 +3,23 @@ // gh-91782: On FreeBSD 12, if the _POSIX_C_SOURCE and _XOPEN_SOURCE macros are // defined, disables C11 support and does not define -// the static_assert() macro. Define the static_assert() macro in Python until -// suports C11: +// the static_assert() macro. // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=255290 -#if defined(__FreeBSD__) && !defined(static_assert) -# define static_assert _Static_assert -#endif - -// static_assert is defined in glibc from version 2.16. Before it requires -// compiler support (gcc >= 4.6) and is called _Static_assert. -// In C++ 11 static_assert is a keyword, redefining is undefined behaviour. -#if (defined(__GLIBC__) \ - && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 16)) \ - && !(defined(__cplusplus) && __cplusplus >= 201103L) \ - && !defined(static_assert)) +// +// macOS <= 10.10 doesn't define static_assert in assert.h at all despite +// having C11 compiler support. +// +// static_assert is defined in glibc from version 2.16. Compiler support for +// the C11 _Static_assert keyword is in gcc >= 4.6. +// +// MSVC makes static_assert a keyword in C11-17, contrary to the standards. +// +// In C++11 and C2x, static_assert is a keyword, redefining is undefined +// behaviour. So only define if building as C (if __STDC_VERSION__ is defined), +// not C++, and only for C11-17. +#if !defined(static_assert) && (defined(__GNUC__) || defined(__clang__)) \ + && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \ + && __STDC_VERSION__ <= 201710L # define static_assert _Static_assert #endif diff --git a/Misc/NEWS.d/next/Build/2023-02-11-05-31-05.gh-issue-99069.X4LDvY.rst b/Misc/NEWS.d/next/Build/2023-02-11-05-31-05.gh-issue-99069.X4LDvY.rst new file mode 100644 index 000000000000..ae9b4d59ca8c --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-02-11-05-31-05.gh-issue-99069.X4LDvY.rst @@ -0,0 +1 @@ +Extended workaround defining ``static_assert`` when missing from the libc headers to all clang and gcc builds. In particular, this fixes building on macOS <= 10.10. From webhook-mailer at python.org Wed Apr 5 12:02:14 2023 From: webhook-mailer at python.org (zooba) Date: Wed, 05 Apr 2023 16:02:14 -0000 Subject: [Python-checkins] gh-103262: Fixes Windows installer build to work with latest compilers (GH-103281) Message-ID: https://github.com/python/cpython/commit/decf7a7cb7daf76c7495d95f1bfe07962a1851cb commit: decf7a7cb7daf76c7495d95f1bfe07962a1851cb branch: 3.10 author: Steve Dower committer: zooba date: 2023-04-05T17:02:04+01:00 summary: gh-103262: Fixes Windows installer build to work with latest compilers (GH-103281) files: A Misc/NEWS.d/next/Build/2023-04-05-15-59-46.gh-issue-103262.nV83ub.rst M Tools/msi/bundle/bootstrap/pythonba.vcxproj diff --git a/Misc/NEWS.d/next/Build/2023-04-05-15-59-46.gh-issue-103262.nV83ub.rst b/Misc/NEWS.d/next/Build/2023-04-05-15-59-46.gh-issue-103262.nV83ub.rst new file mode 100644 index 000000000000..d4bb95559513 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-04-05-15-59-46.gh-issue-103262.nV83ub.rst @@ -0,0 +1 @@ +Fixes Windows installer build to work with latest compilers. diff --git a/Tools/msi/bundle/bootstrap/pythonba.vcxproj b/Tools/msi/bundle/bootstrap/pythonba.vcxproj index e40fb444716e..8b128f6393f3 100644 --- a/Tools/msi/bundle/bootstrap/pythonba.vcxproj +++ b/Tools/msi/bundle/bootstrap/pythonba.vcxproj @@ -21,6 +21,7 @@ Release Win32 + v143 v142 v141 @@ -49,8 +50,7 @@ comctl32.lib;gdiplus.lib;msimg32.lib;shlwapi.lib;wininet.lib;dutil.lib;balutil.lib;version.lib;uxtheme.lib;%(AdditionalDependencies) - $(WixInstallPath)sdk\vs2017\lib\x86 - $(WixInstallPath)sdk\vs2017\lib\x86 + $(WixInstallPath)sdk\vs2017\lib\x86 $(WixInstallPath)sdk\vs2015\lib\x86 $(WixInstallPath)sdk\vs2013\lib\x86 pythonba.def From webhook-mailer at python.org Wed Apr 5 12:37:43 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Wed, 05 Apr 2023 16:37:43 -0000 Subject: [Python-checkins] gh-74690: Further optimise `typing._ProtocolMeta.__instancecheck__` (#103280) Message-ID: https://github.com/python/cpython/commit/de182676853e8de22363e8a0641c42392c0fdaa9 commit: de182676853e8de22363e8a0641c42392c0fdaa9 branch: main author: Alex Waygood committer: AlexWaygood date: 2023-04-05T17:37:36+01:00 summary: gh-74690: Further optimise `typing._ProtocolMeta.__instancecheck__` (#103280) files: M Lib/typing.py diff --git a/Lib/typing.py b/Lib/typing.py index b8420f619a1d..1f1c4ffa2566 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2039,7 +2039,7 @@ def __instancecheck__(cls, instance): val = getattr_static(instance, attr) except AttributeError: break - if callable(getattr(cls, attr, None)) and val is None: + if val is None and callable(getattr(cls, attr, None)): break else: return True From webhook-mailer at python.org Wed Apr 5 17:13:40 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Wed, 05 Apr 2023 21:13:40 -0000 Subject: [Python-checkins] gh-101659: Use the Raw Allocator in the _xxinterpchannels Module (gh-103287) Message-ID: https://github.com/python/cpython/commit/aa5a9b5eb767fd849ea09d0842e33691e690de7c commit: aa5a9b5eb767fd849ea09d0842e33691e690de7c branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-04-05T15:13:12-06:00 summary: gh-101659: Use the Raw Allocator in the _xxinterpchannels Module (gh-103287) Using the raw allocator for any of the global state makes sense, especially as we move to a per-interpreter obmalloc state (gh-101660). files: M Modules/_xxinterpchannelsmodule.c diff --git a/Modules/_xxinterpchannelsmodule.c b/Modules/_xxinterpchannelsmodule.c index fead12c963da..ef1cdcab9522 100644 --- a/Modules/_xxinterpchannelsmodule.c +++ b/Modules/_xxinterpchannelsmodule.c @@ -10,9 +10,77 @@ #include "pycore_interpreteridobject.h" +/* +This module has the following process-global state: + +_globals (static struct globals): + module_count (int) + channels (struct _channels): + numopen (int64_t) + next_id; (int64_t) + mutex (PyThread_type_lock) + head (linked list of struct _channelref *): + id (int64_t) + objcount (Py_ssize_t) + next (struct _channelref *): + ... + chan (struct _channel *): + open (int) + mutex (PyThread_type_lock) + closing (struct _channel_closing *): + ref (struct _channelref *): + ... + ends (struct _channelends *): + numsendopen (int64_t) + numrecvopen (int64_t) + send (struct _channelend *): + interp (int64_t) + open (int) + next (struct _channelend *) + recv (struct _channelend *): + ... + queue (struct _channelqueue *): + count (int64_t) + first (struct _channelitem *): + next (struct _channelitem *): + ... + data (_PyCrossInterpreterData *): + data (void *) + obj (PyObject *) + interp (int64_t) + new_object (xid_newobjectfunc) + free (xid_freefunc) + last (struct _channelitem *): + ... + +The above state includes the following allocations by the module: + +* 1 top-level mutex (to protect the rest of the state) +* for each channel: + * 1 struct _channelref + * 1 struct _channel + * 0-1 struct _channel_closing + * 1 struct _channelends + * 2 struct _channelend + * 1 struct _channelqueue +* for each item in each channel: + * 1 struct _channelitem + * 1 _PyCrossInterpreterData + +The only objects in that global state are the references held by each +channel's queue, which are safely managed via the _PyCrossInterpreterData_*() +API.. The module does not create any objects that are shared globally. +*/ + #define MODULE_NAME "_xxinterpchannels" +#define GLOBAL_MALLOC(TYPE) \ + PyMem_RawMalloc(sizeof(TYPE)) +#define GLOBAL_FREE(VAR) \ + PyMem_RawFree(VAR) + + static PyInterpreterState * _get_current_interp(void) { @@ -301,7 +369,7 @@ typedef struct _channelitem { static _channelitem * _channelitem_new(void) { - _channelitem *item = PyMem_NEW(_channelitem, 1); + _channelitem *item = GLOBAL_MALLOC(_channelitem); if (item == NULL) { PyErr_NoMemory(); return NULL; @@ -316,7 +384,8 @@ _channelitem_clear(_channelitem *item) { if (item->data != NULL) { (void)_release_xid_data(item->data, 1); - PyMem_Free(item->data); + // It was allocated in _channel_send(). + GLOBAL_FREE(item->data); item->data = NULL; } item->next = NULL; @@ -326,7 +395,7 @@ static void _channelitem_free(_channelitem *item) { _channelitem_clear(item); - PyMem_Free(item); + GLOBAL_FREE(item); } static void @@ -357,7 +426,7 @@ typedef struct _channelqueue { static _channelqueue * _channelqueue_new(void) { - _channelqueue *queue = PyMem_NEW(_channelqueue, 1); + _channelqueue *queue = GLOBAL_MALLOC(_channelqueue); if (queue == NULL) { PyErr_NoMemory(); return NULL; @@ -381,7 +450,7 @@ static void _channelqueue_free(_channelqueue *queue) { _channelqueue_clear(queue); - PyMem_Free(queue); + GLOBAL_FREE(queue); } static int @@ -433,7 +502,7 @@ typedef struct _channelend { static _channelend * _channelend_new(int64_t interp) { - _channelend *end = PyMem_NEW(_channelend, 1); + _channelend *end = GLOBAL_MALLOC(_channelend); if (end == NULL) { PyErr_NoMemory(); return NULL; @@ -447,7 +516,7 @@ _channelend_new(int64_t interp) static void _channelend_free(_channelend *end) { - PyMem_Free(end); + GLOBAL_FREE(end); } static void @@ -492,7 +561,7 @@ typedef struct _channelassociations { static _channelends * _channelends_new(void) { - _channelends *ends = PyMem_NEW(_channelends, 1); + _channelends *ends = GLOBAL_MALLOC(_channelends); if (ends== NULL) { return NULL; } @@ -519,7 +588,7 @@ static void _channelends_free(_channelends *ends) { _channelends_clear(ends); - PyMem_Free(ends); + GLOBAL_FREE(ends); } static _channelend * @@ -660,20 +729,20 @@ typedef struct _channel { static _PyChannelState * _channel_new(PyThread_type_lock mutex) { - _PyChannelState *chan = PyMem_NEW(_PyChannelState, 1); + _PyChannelState *chan = GLOBAL_MALLOC(_PyChannelState); if (chan == NULL) { return NULL; } chan->mutex = mutex; chan->queue = _channelqueue_new(); if (chan->queue == NULL) { - PyMem_Free(chan); + GLOBAL_FREE(chan); return NULL; } chan->ends = _channelends_new(); if (chan->ends == NULL) { _channelqueue_free(chan->queue); - PyMem_Free(chan); + GLOBAL_FREE(chan); return NULL; } chan->open = 1; @@ -691,7 +760,7 @@ _channel_free(_PyChannelState *chan) PyThread_release_lock(chan->mutex); PyThread_free_lock(chan->mutex); - PyMem_Free(chan); + GLOBAL_FREE(chan); } static int @@ -814,7 +883,7 @@ typedef struct _channelref { static _channelref * _channelref_new(int64_t id, _PyChannelState *chan) { - _channelref *ref = PyMem_NEW(_channelref, 1); + _channelref *ref = GLOBAL_MALLOC(_channelref); if (ref == NULL) { return NULL; } @@ -841,7 +910,7 @@ _channelref_free(_channelref *ref) _channel_clear_closing(ref->chan); } //_channelref_clear(ref); - PyMem_Free(ref); + GLOBAL_FREE(ref); } static _channelref * @@ -1163,7 +1232,7 @@ _channel_set_closing(struct _channelref *ref, PyThread_type_lock mutex) { res = ERR_CHANNEL_CLOSED; goto done; } - chan->closing = PyMem_NEW(struct _channel_closing, 1); + chan->closing = GLOBAL_MALLOC(struct _channel_closing); if (chan->closing == NULL) { goto done; } @@ -1179,7 +1248,7 @@ static void _channel_clear_closing(struct _channel *chan) { PyThread_acquire_lock(chan->mutex, WAIT_LOCK); if (chan->closing != NULL) { - PyMem_Free(chan->closing); + GLOBAL_FREE(chan->closing); chan->closing = NULL; } PyThread_release_lock(chan->mutex); @@ -1257,14 +1326,14 @@ _channel_send(_channels *channels, int64_t id, PyObject *obj) } // Convert the object to cross-interpreter data. - _PyCrossInterpreterData *data = PyMem_NEW(_PyCrossInterpreterData, 1); + _PyCrossInterpreterData *data = GLOBAL_MALLOC(_PyCrossInterpreterData); if (data == NULL) { PyThread_release_lock(mutex); return -1; } if (_PyObject_GetCrossInterpreterData(obj, data) != 0) { PyThread_release_lock(mutex); - PyMem_Free(data); + GLOBAL_FREE(data); return -1; } @@ -1274,7 +1343,7 @@ _channel_send(_channels *channels, int64_t id, PyObject *obj) if (res != 0) { // We may chain an exception here: (void)_release_xid_data(data, 0); - PyMem_Free(data); + GLOBAL_FREE(data); return res; } @@ -1323,11 +1392,13 @@ _channel_recv(_channels *channels, int64_t id, PyObject **res) if (obj == NULL) { assert(PyErr_Occurred()); (void)_release_xid_data(data, 1); - PyMem_Free(data); + // It was allocated in _channel_send(). + GLOBAL_FREE(data); return -1; } int release_res = _release_xid_data(data, 0); - PyMem_Free(data); + // It was allocated in _channel_send(). + GLOBAL_FREE(data); if (release_res < 0) { // The source interpreter has been destroyed already. assert(PyErr_Occurred()); From webhook-mailer at python.org Wed Apr 5 17:15:56 2023 From: webhook-mailer at python.org (brandtbucher) Date: Wed, 05 Apr 2023 21:15:56 -0000 Subject: [Python-checkins] GH-88691: Shrink the CALL caches (GH-103230) Message-ID: https://github.com/python/cpython/commit/b4978ff872be5102117b4e25d93dbbb4e04c8292 commit: b4978ff872be5102117b4e25d93dbbb4e04c8292 branch: main author: Brandt Bucher committer: brandtbucher date: 2023-04-05T14:15:49-07:00 summary: GH-88691: Shrink the CALL caches (GH-103230) files: A Misc/NEWS.d/next/Core and Builtins/2023-03-25-23-24-38.gh-issue-88691.2SWBd1.rst M Doc/library/dis.rst M Include/internal/pycore_code.h M Include/internal/pycore_opcode.h M Lib/importlib/_bootstrap_external.py M Lib/opcode.py M Lib/test/test_dis.py M Programs/test_frozenmain.h M Python/bytecodes.c M Python/generated_cases.c.h M Python/opcode_metadata.h M Python/specialize.c diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 8703cddb3448..19c08b225ef2 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -59,7 +59,7 @@ the following command can be used to display the disassembly of 3 2 LOAD_GLOBAL 1 (NULL + len) 12 LOAD_FAST 0 (alist) 14 CALL 1 - 24 RETURN_VALUE + 22 RETURN_VALUE (The "2" is a line number). diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 7f3148a38ff1..faf1be585e17 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -73,7 +73,6 @@ typedef struct { typedef struct { uint16_t counter; uint16_t func_version[2]; - uint16_t min_args; } _PyCallCache; #define INLINE_CACHE_ENTRIES_CALL CACHE_ENTRIES(_PyCallCache) diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 58f7da51aebd..81ca91465950 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -55,7 +55,7 @@ const uint8_t _PyOpcode_Caches[256] = { [LOAD_GLOBAL] = 4, [BINARY_OP] = 1, [SEND] = 1, - [CALL] = 4, + [CALL] = 3, }; const uint8_t _PyOpcode_Deopt[256] = { diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 9c4c5f907744..de6c434450fc 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -438,6 +438,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12a7 3522 (Removed JUMP_IF_FALSE_OR_POP/JUMP_IF_TRUE_OR_POP) # Python 3.12a7 3523 (Convert COMPARE_AND_BRANCH back to COMPARE_OP) # Python 3.12a7 3524 (Shrink the BINARY_SUBSCR caches) +# Python 3.12b1 3525 (Shrink the CALL caches) # Python 3.13 will start with 3550 @@ -454,7 +455,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3524).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3525).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/opcode.py b/Lib/opcode.py index 16a61dff47b5..b62dfa1bcb42 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -410,7 +410,6 @@ def pseudo_op(name, op, real_ops): "CALL": { "counter": 1, "func_version": 2, - "min_args": 1, }, "STORE_SUBSCR": { "counter": 1, diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 7e501045662f..4a2144743f65 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -138,10 +138,10 @@ def bug708901(): %3d CALL 2 GET_ITER - >> FOR_ITER 2 (to 36) + >> FOR_ITER 2 (to 34) STORE_FAST 0 (res) -%3d JUMP_BACKWARD 4 (to 28) +%3d JUMP_BACKWARD 4 (to 26) %3d >> END_FOR RETURN_CONST 0 (None) @@ -437,7 +437,7 @@ def _with(c): %3d >> PUSH_EXC_INFO WITH_EXCEPT_START - POP_JUMP_IF_TRUE 1 (to 44) + POP_JUMP_IF_TRUE 1 (to 42) RERAISE 2 >> POP_TOP POP_EXCEPT @@ -492,10 +492,10 @@ async def _asyncwith(c): CALL 2 GET_AWAITABLE 2 LOAD_CONST 0 (None) - >> SEND 3 (to 64) + >> SEND 3 (to 62) YIELD_VALUE 2 RESUME 3 - JUMP_BACKWARD_NO_INTERRUPT 5 (to 54) + JUMP_BACKWARD_NO_INTERRUPT 5 (to 52) >> POP_TOP POP_TOP @@ -504,21 +504,21 @@ async def _asyncwith(c): RETURN_CONST 0 (None) %3d >> CLEANUP_THROW - JUMP_BACKWARD 27 (to 24) + JUMP_BACKWARD 26 (to 24) >> CLEANUP_THROW - JUMP_BACKWARD 9 (to 64) + JUMP_BACKWARD 9 (to 62) >> PUSH_EXC_INFO WITH_EXCEPT_START GET_AWAITABLE 2 LOAD_CONST 0 (None) - >> SEND 4 (to 102) + >> SEND 4 (to 100) YIELD_VALUE 3 RESUME 3 - JUMP_BACKWARD_NO_INTERRUPT 5 (to 90) + JUMP_BACKWARD_NO_INTERRUPT 5 (to 88) >> CLEANUP_THROW >> SWAP 2 POP_TOP - POP_JUMP_IF_TRUE 1 (to 110) + POP_JUMP_IF_TRUE 1 (to 108) RERAISE 2 >> POP_TOP POP_EXCEPT @@ -730,14 +730,14 @@ def loop_test(): LOAD_CONST 2 (3) BINARY_OP 5 (*) GET_ITER - >> FOR_ITER_LIST 14 (to 48) + >> FOR_ITER_LIST 13 (to 46) STORE_FAST 0 (i) %3d LOAD_GLOBAL_MODULE 1 (NULL + load_test) LOAD_FAST 0 (i) CALL_PY_WITH_DEFAULTS 1 POP_TOP - JUMP_BACKWARD 16 (to 16) + JUMP_BACKWARD 15 (to 16) %3d >> END_FOR RETURN_CONST 0 (None) @@ -1193,7 +1193,7 @@ def test_show_caches(self): caches = list(self.get_cached_values(quickened, adaptive)) for cache in caches: self.assertRegex(cache, pattern) - total_caches = 22 + total_caches = 20 empty_caches = 7 self.assertEqual(caches.count(""), empty_caches) self.assertEqual(len(caches), total_caches) @@ -1524,9 +1524,9 @@ def _prepare_test_cases(): Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='Hello world!', argrepr="'Hello world!'", offset=42, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=7, argval=7, argrepr='', offset=44, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=54, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=56, starts_line=8, is_jump_target=False, positions=None), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=58, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=52, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=54, starts_line=8, is_jump_target=False, positions=None), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=56, starts_line=None, is_jump_target=False, positions=None), ] expected_opinfo_f = [ @@ -1549,9 +1549,9 @@ def _prepare_test_cases(): Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=40, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=42, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=4, argval=4, argrepr='', offset=44, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=54, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=56, starts_line=6, is_jump_target=False, positions=None), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=58, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=52, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=54, starts_line=6, is_jump_target=False, positions=None), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=56, starts_line=None, is_jump_target=False, positions=None), ] expected_opinfo_inner = [ @@ -1565,8 +1565,8 @@ def _prepare_test_cases(): Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=22, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=24, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=6, argval=6, argrepr='', offset=26, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=36, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RETURN_CONST', opcode=121, arg=0, argval=None, argrepr='None', offset=38, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=34, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RETURN_CONST', opcode=121, arg=0, argval=None, argrepr='None', offset=36, starts_line=None, is_jump_target=False, positions=None), ] expected_opinfo_jumpy = [ @@ -1574,115 +1574,115 @@ def _prepare_test_cases(): Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='range', argrepr='NULL + range', offset=2, starts_line=3, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=12, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=14, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=24, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='FOR_ITER', opcode=93, arg=27, argval=84, argrepr='to 84', offset=26, starts_line=None, is_jump_target=True, positions=None), - Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=30, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=32, starts_line=4, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=42, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=44, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=54, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=56, starts_line=5, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=58, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_OP', opcode=107, arg=2, argval='<', argrepr='<', offset=60, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=68, argrepr='to 68', offset=64, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=21, argval=26, argrepr='to 26', offset=66, starts_line=6, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=68, starts_line=7, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=70, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_OP', opcode=107, arg=68, argval='>', argrepr='>', offset=72, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=80, argrepr='to 80', offset=76, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=27, argval=26, argrepr='to 26', offset=78, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=80, starts_line=8, is_jump_target=True, positions=None), - Instruction(opname='JUMP_FORWARD', opcode=110, arg=13, argval=110, argrepr='to 110', offset=82, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='END_FOR', opcode=4, arg=None, argval=None, argrepr='', offset=84, starts_line=3, is_jump_target=True, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=86, starts_line=10, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=96, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=98, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=108, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST_CHECK', opcode=127, arg=0, argval='i', argrepr='i', offset=110, starts_line=11, is_jump_target=True, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=32, argval=178, argrepr='to 178', offset=112, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=114, starts_line=12, is_jump_target=True, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=124, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=126, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=136, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=138, starts_line=13, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=140, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='BINARY_OP', opcode=122, arg=23, argval=23, argrepr='-=', offset=142, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=146, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=148, starts_line=14, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=150, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_OP', opcode=107, arg=68, argval='>', argrepr='>', offset=152, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=160, argrepr='to 160', offset=156, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=25, argval=110, argrepr='to 110', offset=158, starts_line=15, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=160, starts_line=16, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=162, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_OP', opcode=107, arg=2, argval='<', argrepr='<', offset=164, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=172, argrepr='to 172', offset=168, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_FORWARD', opcode=110, arg=15, argval=202, argrepr='to 202', offset=170, starts_line=17, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=172, starts_line=11, is_jump_target=True, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=178, argrepr='to 178', offset=174, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=32, argval=114, argrepr='to 114', offset=176, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=178, starts_line=19, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=188, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=190, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=200, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=202, starts_line=20, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=204, starts_line=21, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=206, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=208, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=212, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=214, starts_line=25, is_jump_target=False, positions=None), - Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=216, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=218, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=220, starts_line=26, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=230, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=232, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=242, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=244, starts_line=25, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=246, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=248, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=250, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=260, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=262, starts_line=28, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=272, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=274, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=22, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='FOR_ITER', opcode=93, arg=26, argval=80, argrepr='to 80', offset=24, starts_line=None, is_jump_target=True, positions=None), + Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=28, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=30, starts_line=4, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=40, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=42, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=50, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=52, starts_line=5, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=54, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=2, argval='<', argrepr='<', offset=56, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=64, argrepr='to 64', offset=60, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=20, argval=24, argrepr='to 24', offset=62, starts_line=6, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=64, starts_line=7, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=66, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=68, argval='>', argrepr='>', offset=68, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=76, argrepr='to 76', offset=72, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=26, argval=24, argrepr='to 24', offset=74, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=76, starts_line=8, is_jump_target=True, positions=None), + Instruction(opname='JUMP_FORWARD', opcode=110, arg=12, argval=104, argrepr='to 104', offset=78, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='END_FOR', opcode=4, arg=None, argval=None, argrepr='', offset=80, starts_line=3, is_jump_target=True, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=82, starts_line=10, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=92, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=94, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=102, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST_CHECK', opcode=127, arg=0, argval='i', argrepr='i', offset=104, starts_line=11, is_jump_target=True, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=31, argval=170, argrepr='to 170', offset=106, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=108, starts_line=12, is_jump_target=True, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=118, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=120, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=128, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=130, starts_line=13, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=132, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='BINARY_OP', opcode=122, arg=23, argval=23, argrepr='-=', offset=134, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=138, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=140, starts_line=14, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=142, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=68, argval='>', argrepr='>', offset=144, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=152, argrepr='to 152', offset=148, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=24, argval=104, argrepr='to 104', offset=150, starts_line=15, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=152, starts_line=16, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=154, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=2, argval='<', argrepr='<', offset=156, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=164, argrepr='to 164', offset=160, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_FORWARD', opcode=110, arg=14, argval=192, argrepr='to 192', offset=162, starts_line=17, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=164, starts_line=11, is_jump_target=True, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=170, argrepr='to 170', offset=166, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=31, argval=108, argrepr='to 108', offset=168, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=170, starts_line=19, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=180, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=182, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=190, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=192, starts_line=20, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=194, starts_line=21, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=196, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=198, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=202, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=204, starts_line=25, is_jump_target=False, positions=None), + Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=206, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=208, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=210, starts_line=26, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=220, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=222, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=230, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=232, starts_line=25, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=234, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=236, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=238, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=246, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=248, starts_line=28, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=258, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=260, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=268, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RETURN_CONST', opcode=121, arg=0, argval=None, argrepr='None', offset=270, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=272, starts_line=25, is_jump_target=False, positions=None), + Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=274, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=280, argrepr='to 280', offset=276, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=278, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=280, starts_line=None, is_jump_target=True, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=282, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=284, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RETURN_CONST', opcode=121, arg=0, argval=None, argrepr='None', offset=286, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=288, starts_line=25, is_jump_target=False, positions=None), - Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=290, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=296, argrepr='to 296', offset=292, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=294, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=296, starts_line=None, is_jump_target=True, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=298, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=300, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=302, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=22, argval=262, argrepr='to 262', offset=304, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=306, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=308, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=310, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=312, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=314, starts_line=22, is_jump_target=False, positions=None), - Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=324, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=15, argval=358, argrepr='to 358', offset=326, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=328, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=330, starts_line=23, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=340, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=342, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=352, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=354, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=48, argval=262, argrepr='to 262', offset=356, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=358, starts_line=22, is_jump_target=True, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=360, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=362, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=364, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=366, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=368, starts_line=28, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=378, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=380, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=390, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=392, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=394, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=396, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=398, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=286, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=21, argval=248, argrepr='to 248', offset=288, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=290, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=292, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=294, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=296, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=298, starts_line=22, is_jump_target=False, positions=None), + Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=308, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=14, argval=340, argrepr='to 340', offset=310, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=312, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=314, starts_line=23, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=324, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=326, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=334, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=336, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=46, argval=248, argrepr='to 248', offset=338, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=340, starts_line=22, is_jump_target=True, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=342, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=344, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=346, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=348, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=350, starts_line=28, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=360, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=362, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=370, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=372, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=374, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=376, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=378, starts_line=None, is_jump_target=False, positions=None), ] # One last piece of inspect fodder to check the default line number handling diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-25-23-24-38.gh-issue-88691.2SWBd1.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-25-23-24-38.gh-issue-88691.2SWBd1.rst new file mode 100644 index 000000000000..761d45b0a3a8 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-25-23-24-38.gh-issue-88691.2SWBd1.rst @@ -0,0 +1 @@ +Reduce the number of inline :opcode:`CACHE` entries for :opcode:`CALL`. diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index c33bb18f4da8..4ac472a88261 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -1,38 +1,38 @@ // Auto-generated by Programs/freeze_test_frozenmain.py unsigned char M_test_frozenmain[] = { 227,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, - 0,0,0,0,0,243,170,0,0,0,151,0,100,0,100,1, + 0,0,0,0,0,243,162,0,0,0,151,0,100,0,100,1, 108,0,90,0,100,0,100,1,108,1,90,1,2,0,101,2, - 100,2,171,1,0,0,0,0,0,0,0,0,1,0,2,0, - 101,2,100,3,101,0,106,6,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,171,2,0,0,0,0, - 0,0,0,0,1,0,2,0,101,1,106,8,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,171,0, - 0,0,0,0,0,0,0,0,100,4,25,0,0,0,90,5, - 100,5,68,0,93,20,0,0,90,6,2,0,101,2,100,6, - 101,6,155,0,100,7,101,5,101,6,25,0,0,0,155,0, - 157,4,171,1,0,0,0,0,0,0,0,0,1,0,140,22, - 4,0,121,1,41,8,233,0,0,0,0,78,122,18,70,114, - 111,122,101,110,32,72,101,108,108,111,32,87,111,114,108,100, - 122,8,115,121,115,46,97,114,103,118,218,6,99,111,110,102, - 105,103,41,5,218,12,112,114,111,103,114,97,109,95,110,97, - 109,101,218,10,101,120,101,99,117,116,97,98,108,101,218,15, - 117,115,101,95,101,110,118,105,114,111,110,109,101,110,116,218, - 17,99,111,110,102,105,103,117,114,101,95,99,95,115,116,100, - 105,111,218,14,98,117,102,102,101,114,101,100,95,115,116,100, - 105,111,122,7,99,111,110,102,105,103,32,122,2,58,32,41, - 7,218,3,115,121,115,218,17,95,116,101,115,116,105,110,116, - 101,114,110,97,108,99,97,112,105,218,5,112,114,105,110,116, - 218,4,97,114,103,118,218,11,103,101,116,95,99,111,110,102, - 105,103,115,114,3,0,0,0,218,3,107,101,121,169,0,243, - 0,0,0,0,250,18,116,101,115,116,95,102,114,111,122,101, - 110,109,97,105,110,46,112,121,250,8,60,109,111,100,117,108, - 101,62,114,18,0,0,0,1,0,0,0,115,100,0,0,0, - 240,3,1,1,1,243,8,0,1,11,219,0,24,225,0,5, - 208,6,26,213,0,27,217,0,5,128,106,144,35,151,40,145, - 40,213,0,27,216,9,38,208,9,26,215,9,38,209,9,38, - 212,9,40,168,24,209,9,50,128,6,240,2,6,12,2,242, - 0,7,1,42,128,67,241,14,0,5,10,208,10,40,144,67, - 209,10,40,152,54,160,35,153,59,209,10,40,214,4,41,241, - 15,7,1,42,114,16,0,0,0, + 100,2,171,1,0,0,0,0,0,0,1,0,2,0,101,2, + 100,3,101,0,106,6,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,171,2,0,0,0,0,0,0, + 1,0,2,0,101,1,106,8,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,171,0,0,0,0,0, + 0,0,100,4,25,0,0,0,90,5,100,5,68,0,93,19, + 0,0,90,6,2,0,101,2,100,6,101,6,155,0,100,7, + 101,5,101,6,25,0,0,0,155,0,157,4,171,1,0,0, + 0,0,0,0,1,0,140,21,4,0,121,1,41,8,233,0, + 0,0,0,78,122,18,70,114,111,122,101,110,32,72,101,108, + 108,111,32,87,111,114,108,100,122,8,115,121,115,46,97,114, + 103,118,218,6,99,111,110,102,105,103,41,5,218,12,112,114, + 111,103,114,97,109,95,110,97,109,101,218,10,101,120,101,99, + 117,116,97,98,108,101,218,15,117,115,101,95,101,110,118,105, + 114,111,110,109,101,110,116,218,17,99,111,110,102,105,103,117, + 114,101,95,99,95,115,116,100,105,111,218,14,98,117,102,102, + 101,114,101,100,95,115,116,100,105,111,122,7,99,111,110,102, + 105,103,32,122,2,58,32,41,7,218,3,115,121,115,218,17, + 95,116,101,115,116,105,110,116,101,114,110,97,108,99,97,112, + 105,218,5,112,114,105,110,116,218,4,97,114,103,118,218,11, + 103,101,116,95,99,111,110,102,105,103,115,114,3,0,0,0, + 218,3,107,101,121,169,0,243,0,0,0,0,250,18,116,101, + 115,116,95,102,114,111,122,101,110,109,97,105,110,46,112,121, + 250,8,60,109,111,100,117,108,101,62,114,18,0,0,0,1, + 0,0,0,115,100,0,0,0,240,3,1,1,1,243,8,0, + 1,11,219,0,24,225,0,5,208,6,26,212,0,27,217,0, + 5,128,106,144,35,151,40,145,40,212,0,27,216,9,38,208, + 9,26,215,9,38,209,9,38,211,9,40,168,24,209,9,50, + 128,6,240,2,6,12,2,242,0,7,1,42,128,67,241,14, + 0,5,10,208,10,40,144,67,209,10,40,152,54,160,35,153, + 59,209,10,40,213,4,41,241,15,7,1,42,114,16,0,0, + 0, }; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 617b6f311e2f..72f85cc92b0c 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2318,7 +2318,7 @@ dummy_func( kwnames = GETITEM(frame->f_code->co_consts, oparg); } - // Cache layout: counter/1, func_version/2, min_args/1 + // Cache layout: counter/1, func_version/2 // Neither CALL_INTRINSIC_1/2 nor CALL_FUNCTION_EX are members! family(call, INLINE_CACHE_ENTRIES_CALL) = { CALL, @@ -2348,7 +2348,7 @@ dummy_func( // (Some args may be keywords, see KW_NAMES, which sets 'kwnames'.) // On exit, the stack is [result]. // When calling Python, inline the call using DISPATCH_INLINED(). - inst(CALL, (unused/1, unused/2, unused/1, method, callable, args[oparg] -- res)) { + inst(CALL, (unused/1, unused/2, method, callable, args[oparg] -- res)) { int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -2426,7 +2426,7 @@ dummy_func( // Start out with [NULL, bound_method, arg1, arg2, ...] // Transform to [callable, self, arg1, arg2, ...] // Then fall through to CALL_PY_EXACT_ARGS - inst(CALL_BOUND_METHOD_EXACT_ARGS, (unused/1, unused/2, unused/1, method, callable, unused[oparg] -- unused)) { + inst(CALL_BOUND_METHOD_EXACT_ARGS, (unused/1, unused/2, method, callable, unused[oparg] -- unused)) { DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -2438,7 +2438,7 @@ dummy_func( GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); } - inst(CALL_PY_EXACT_ARGS, (unused/1, func_version/2, unused/1, method, callable, args[oparg] -- unused)) { + inst(CALL_PY_EXACT_ARGS, (unused/1, func_version/2, method, callable, args[oparg] -- unused)) { assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -2465,7 +2465,7 @@ dummy_func( DISPATCH_INLINED(new_frame); } - inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, min_args/1, method, callable, args[oparg] -- unused)) { + inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, method, callable, args[oparg] -- unused)) { assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -2479,6 +2479,11 @@ dummy_func( PyFunctionObject *func = (PyFunctionObject *)callable; DEOPT_IF(func->func_version != func_version, CALL); PyCodeObject *code = (PyCodeObject *)func->func_code; + assert(func->func_defaults); + assert(PyTuple_CheckExact(func->func_defaults)); + int defcount = (int)PyTuple_GET_SIZE(func->func_defaults); + assert(defcount <= code->co_argcount); + int min_args = code->co_argcount - defcount; DEOPT_IF(argcount > code->co_argcount, CALL); DEOPT_IF(argcount < min_args, CALL); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); @@ -2497,7 +2502,7 @@ dummy_func( DISPATCH_INLINED(new_frame); } - inst(CALL_NO_KW_TYPE_1, (unused/1, unused/2, unused/1, null, callable, args[oparg] -- res)) { + inst(CALL_NO_KW_TYPE_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) { assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -2510,7 +2515,7 @@ dummy_func( Py_DECREF(&PyType_Type); // I.e., callable } - inst(CALL_NO_KW_STR_1, (unused/1, unused/2, unused/1, null, callable, args[oparg] -- res)) { + inst(CALL_NO_KW_STR_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) { assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -2525,7 +2530,7 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_TUPLE_1, (unused/1, unused/2, unused/1, null, callable, args[oparg] -- res)) { + inst(CALL_NO_KW_TUPLE_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) { assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -2539,7 +2544,7 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_BUILTIN_CLASS, (unused/1, unused/2, unused/1, method, callable, args[oparg] -- res)) { + inst(CALL_BUILTIN_CLASS, (unused/1, unused/2, method, callable, args[oparg] -- res)) { int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -2564,7 +2569,7 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_BUILTIN_O, (unused/1, unused/2, unused/1, method, callable, args[oparg] -- res)) { + inst(CALL_NO_KW_BUILTIN_O, (unused/1, unused/2, method, callable, args[oparg] -- res)) { assert(cframe.use_tracing == 0); /* Builtin METH_O functions */ assert(kwnames == NULL); @@ -2596,7 +2601,7 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_BUILTIN_FAST, (unused/1, unused/2, unused/1, method, callable, args[oparg] -- res)) { + inst(CALL_NO_KW_BUILTIN_FAST, (unused/1, unused/2, method, callable, args[oparg] -- res)) { assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); @@ -2632,7 +2637,7 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_BUILTIN_FAST_WITH_KEYWORDS, (unused/1, unused/2, unused/1, method, callable, args[oparg] -- res)) { + inst(CALL_BUILTIN_FAST_WITH_KEYWORDS, (unused/1, unused/2, method, callable, args[oparg] -- res)) { assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; @@ -2668,7 +2673,7 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_LEN, (unused/1, unused/2, unused/1, method, callable, args[oparg] -- res)) { + inst(CALL_NO_KW_LEN, (unused/1, unused/2, method, callable, args[oparg] -- res)) { assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* len(o) */ @@ -2696,7 +2701,7 @@ dummy_func( ERROR_IF(res == NULL, error); } - inst(CALL_NO_KW_ISINSTANCE, (unused/1, unused/2, unused/1, method, callable, args[oparg] -- res)) { + inst(CALL_NO_KW_ISINSTANCE, (unused/1, unused/2, method, callable, args[oparg] -- res)) { assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* isinstance(o, o2) */ @@ -2727,7 +2732,7 @@ dummy_func( } // This is secretly a super-instruction - inst(CALL_NO_KW_LIST_APPEND, (unused/1, unused/2, unused/1, method, self, args[oparg] -- unused)) { + inst(CALL_NO_KW_LIST_APPEND, (unused/1, unused/2, method, self, args[oparg] -- unused)) { assert(cframe.use_tracing == 0); assert(kwnames == NULL); assert(oparg == 1); @@ -2748,7 +2753,7 @@ dummy_func( DISPATCH(); } - inst(CALL_NO_KW_METHOD_DESCRIPTOR_O, (unused/1, unused/2, unused/1, method, unused, args[oparg] -- res)) { + inst(CALL_NO_KW_METHOD_DESCRIPTOR_O, (unused/1, unused/2, method, unused, args[oparg] -- res)) { assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -2782,7 +2787,7 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, (unused/1, unused/2, unused/1, method, unused, args[oparg] -- res)) { + inst(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, (unused/1, unused/2, method, unused, args[oparg] -- res)) { int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -2814,7 +2819,7 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, (unused/1, unused/2, unused/1, method, unused, args[oparg] -- res)) { + inst(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, (unused/1, unused/2, method, unused, args[oparg] -- res)) { assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -2846,7 +2851,7 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_METHOD_DESCRIPTOR_FAST, (unused/1, unused/2, unused/1, method, unused, args[oparg] -- res)) { + inst(CALL_NO_KW_METHOD_DESCRIPTOR_FAST, (unused/1, unused/2, method, unused, args[oparg] -- res)) { assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 7df585be0bef..420d136bb981 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3301,7 +3301,7 @@ TARGET(CALL) { PREDICTED(CALL); - static_assert(INLINE_CACHE_ENTRIES_CALL == 4, "incorrect cache size"); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; @@ -3382,7 +3382,7 @@ STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3442,7 +3442,6 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - uint16_t min_args = read_u16(&next_instr[3].cache); #line 2469 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); @@ -3457,6 +3456,11 @@ PyFunctionObject *func = (PyFunctionObject *)callable; DEOPT_IF(func->func_version != func_version, CALL); PyCodeObject *code = (PyCodeObject *)func->func_code; + assert(func->func_defaults); + assert(PyTuple_CheckExact(func->func_defaults)); + int defcount = (int)PyTuple_GET_SIZE(func->func_defaults); + assert(defcount <= code->co_argcount); + int min_args = code->co_argcount - defcount; DEOPT_IF(argcount > code->co_argcount, CALL); DEOPT_IF(argcount < min_args, CALL); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); @@ -3473,7 +3477,7 @@ STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); DISPATCH_INLINED(new_frame); - #line 3477 "Python/generated_cases.c.h" + #line 3481 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3481,7 +3485,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2501 "Python/bytecodes.c" + #line 2506 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3492,11 +3496,11 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3496 "Python/generated_cases.c.h" + #line 3500 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + next_instr += 3; DISPATCH(); } @@ -3505,7 +3509,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2514 "Python/bytecodes.c" + #line 2519 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3517,11 +3521,11 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3521 "Python/generated_cases.c.h" + #line 3525 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3531,7 +3535,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2529 "Python/bytecodes.c" + #line 2534 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3542,11 +3546,11 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3546 "Python/generated_cases.c.h" + #line 3550 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3556,7 +3560,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2543 "Python/bytecodes.c" + #line 2548 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3578,11 +3582,11 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3582 "Python/generated_cases.c.h" + #line 3586 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3592,7 +3596,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2568 "Python/bytecodes.c" + #line 2573 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_O functions */ assert(kwnames == NULL); @@ -3621,11 +3625,11 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3625 "Python/generated_cases.c.h" + #line 3629 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3635,7 +3639,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2600 "Python/bytecodes.c" + #line 2605 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); @@ -3668,11 +3672,11 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 3672 "Python/generated_cases.c.h" + #line 3676 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3682,7 +3686,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2636 "Python/bytecodes.c" + #line 2641 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; @@ -3715,11 +3719,11 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3719 "Python/generated_cases.c.h" + #line 3723 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3729,7 +3733,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2672 "Python/bytecodes.c" + #line 2677 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* len(o) */ @@ -3755,11 +3759,11 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3759 "Python/generated_cases.c.h" + #line 3763 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + next_instr += 3; DISPATCH(); } @@ -3768,7 +3772,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2700 "Python/bytecodes.c" + #line 2705 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* isinstance(o, o2) */ @@ -3796,11 +3800,11 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3800 "Python/generated_cases.c.h" + #line 3804 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + next_instr += 3; DISPATCH(); } @@ -3808,7 +3812,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2731 "Python/bytecodes.c" + #line 2736 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); assert(oparg == 1); @@ -3827,14 +3831,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 3831 "Python/generated_cases.c.h" + #line 3835 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2752 "Python/bytecodes.c" + #line 2757 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -3865,11 +3869,11 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3869 "Python/generated_cases.c.h" + #line 3873 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3878,7 +3882,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2786 "Python/bytecodes.c" + #line 2791 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3907,11 +3911,11 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3911 "Python/generated_cases.c.h" + #line 3915 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3920,7 +3924,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2818 "Python/bytecodes.c" + #line 2823 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -3949,11 +3953,11 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3953 "Python/generated_cases.c.h" + #line 3957 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3962,7 +3966,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2850 "Python/bytecodes.c" + #line 2855 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -3990,11 +3994,11 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3994 "Python/generated_cases.c.h" + #line 3998 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -4005,7 +4009,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 2881 "Python/bytecodes.c" + #line 2886 "Python/bytecodes.c" if (oparg & 1) { // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. @@ -4024,15 +4028,15 @@ assert(PyTuple_CheckExact(callargs)); result = do_call_core(tstate, func, callargs, kwargs, cframe.use_tracing); - #line 4028 "Python/generated_cases.c.h" + #line 4032 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 2900 "Python/bytecodes.c" + #line 2905 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4036 "Python/generated_cases.c.h" + #line 4040 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4047,7 +4051,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; - #line 2911 "Python/bytecodes.c" + #line 2916 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4076,14 +4080,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4080 "Python/generated_cases.c.h" + #line 4084 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 2942 "Python/bytecodes.c" + #line 2947 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4104,7 +4108,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4108 "Python/generated_cases.c.h" + #line 4112 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4112,15 +4116,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 2965 "Python/bytecodes.c" + #line 2970 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4118 "Python/generated_cases.c.h" + #line 4122 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 2967 "Python/bytecodes.c" + #line 2972 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4124 "Python/generated_cases.c.h" + #line 4128 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4131,7 +4135,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 2971 "Python/bytecodes.c" + #line 2976 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4166,7 +4170,7 @@ Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4170 "Python/generated_cases.c.h" + #line 4174 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4175,10 +4179,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3008 "Python/bytecodes.c" + #line 3013 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4182 "Python/generated_cases.c.h" + #line 4186 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4190,7 +4194,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3013 "Python/bytecodes.c" + #line 3018 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4206,12 +4210,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4210 "Python/generated_cases.c.h" + #line 4214 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3029 "Python/bytecodes.c" + #line 3034 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4215 "Python/generated_cases.c.h" + #line 4219 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4221,27 +4225,27 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3034 "Python/bytecodes.c" + #line 3039 "Python/bytecodes.c" assert(oparg >= 2); - #line 4227 "Python/generated_cases.c.h" + #line 4231 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3038 "Python/bytecodes.c" + #line 3043 "Python/bytecodes.c" assert(oparg); assert(cframe.use_tracing == 0); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4241 "Python/generated_cases.c.h" + #line 4245 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3047 "Python/bytecodes.c" + #line 3052 "Python/bytecodes.c" Py_UNREACHABLE(); - #line 4247 "Python/generated_cases.c.h" + #line 4251 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 5c984eb4ae12..f57b76aeb310 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -695,7 +695,7 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { } #endif -enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; +enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; struct opcode_metadata { bool valid_entry; enum InstructionFormat instr_format; @@ -844,24 +844,24 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000 }, [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000 }, [KW_NAMES] = { true, INSTR_FMT_IB }, - [CALL] = { true, INSTR_FMT_IBC000 }, - [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC000 }, - [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC000 }, - [CALL_PY_WITH_DEFAULTS] = { true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_TYPE_1] = { true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_STR_1] = { true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_TUPLE_1] = { true, INSTR_FMT_IBC000 }, - [CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_BUILTIN_O] = { true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_BUILTIN_FAST] = { true, INSTR_FMT_IBC000 }, - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_LEN] = { true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_ISINSTANCE] = { true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_LIST_APPEND] = { true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC000 }, - [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC000 }, + [CALL] = { true, INSTR_FMT_IBC00 }, + [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00 }, + [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00 }, + [CALL_PY_WITH_DEFAULTS] = { true, INSTR_FMT_IBC00 }, + [CALL_NO_KW_TYPE_1] = { true, INSTR_FMT_IBC00 }, + [CALL_NO_KW_STR_1] = { true, INSTR_FMT_IBC00 }, + [CALL_NO_KW_TUPLE_1] = { true, INSTR_FMT_IBC00 }, + [CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC00 }, + [CALL_NO_KW_BUILTIN_O] = { true, INSTR_FMT_IBC00 }, + [CALL_NO_KW_BUILTIN_FAST] = { true, INSTR_FMT_IBC00 }, + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00 }, + [CALL_NO_KW_LEN] = { true, INSTR_FMT_IBC00 }, + [CALL_NO_KW_ISINSTANCE] = { true, INSTR_FMT_IBC00 }, + [CALL_NO_KW_LIST_APPEND] = { true, INSTR_FMT_IBC00 }, + [CALL_NO_KW_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC00 }, + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00 }, + [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00 }, + [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00 }, [CALL_FUNCTION_EX] = { true, INSTR_FMT_IB }, [MAKE_FUNCTION] = { true, INSTR_FMT_IB }, [RETURN_GENERATOR] = { true, INSTR_FMT_IX }, diff --git a/Python/specialize.c b/Python/specialize.c index 9187438d519b..a9d3226ee39f 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1627,17 +1627,12 @@ specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs, assert(nargs <= argcount && nargs >= min_args); assert(min_args >= 0 && defcount >= 0); assert(defcount == 0 || func->func_defaults != NULL); - if (min_args > 0xffff) { - SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_RANGE); - return -1; - } int version = _PyFunction_GetVersionForCurrentState(func); if (version == 0) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_VERSIONS); return -1; } write_u32(cache->func_version, version); - cache->min_args = min_args; if (argcount == nargs) { instr->op.code = bound_method ? CALL_BOUND_METHOD_EXACT_ARGS : CALL_PY_EXACT_ARGS; } From webhook-mailer at python.org Wed Apr 5 20:33:59 2023 From: webhook-mailer at python.org (ethanfurman) Date: Thu, 06 Apr 2023 00:33:59 -0000 Subject: [Python-checkins] gh-93910: [Enum] remove member.member deprecation (GH-103236) Message-ID: https://github.com/python/cpython/commit/4ec8dd10bd4682793559c4eccbcf6ae00688c4c3 commit: 4ec8dd10bd4682793559c4eccbcf6ae00688c4c3 branch: main author: Ethan Furman committer: ethanfurman date: 2023-04-05T17:33:52-07:00 summary: gh-93910: [Enum] remove member.member deprecation (GH-103236) i.e. Color.RED.BLUE is now officially supported. files: A Misc/NEWS.d/next/Library/2023-04-04-12-43-38.gh-issue-93910.jurMzv.rst M Doc/howto/enum.rst M Lib/enum.py M Lib/test/test_enum.py diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst index 38951ed7348f..9390faded2fb 100644 --- a/Doc/howto/enum.rst +++ b/Doc/howto/enum.rst @@ -988,12 +988,11 @@ but remain normal attributes. """""""""""""""""""" Enum members are instances of their enum class, and are normally accessed as -``EnumClass.member``. In Python versions starting with ``3.5`` you could access -members from other members -- this practice is discouraged, is deprecated -in ``3.12``, and will be removed in ``3.14``. +``EnumClass.member``. In certain situations, such as writing custom enum +behavior, being able to access one member directly from another is useful, +and is supported. .. versionchanged:: 3.5 -.. versionchanged:: 3.12 Creating members that are mixed with other data types diff --git a/Lib/enum.py b/Lib/enum.py index ec698d5fa3c3..0b0629cf9205 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -201,23 +201,13 @@ def __get__(self, instance, ownerclass=None): ) else: if self.fget is None: - if self.member is None: # not sure this can happen, but just in case + # look for a member by this name. + try: + return ownerclass._member_map_[self.name] + except KeyError: raise AttributeError( '%r has no attribute %r' % (ownerclass, self.name) ) - # issue warning deprecating this behavior - import warnings - warnings.warn( - "`member.member` access (e.g. `Color.RED.BLUE`) is " - "deprecated and will be removed in 3.14.", - DeprecationWarning, - stacklevel=2, - ) - return self.member - # XXX: uncomment in 3.14 and remove warning above - # raise AttributeError( - # '%r member has no attribute %r' % (ownerclass, self.name) - # ) else: return self.fget(instance) @@ -314,22 +304,32 @@ def __set_name__(self, enum_class, member_name): ): # no other instances found, record this member in _member_names_ enum_class._member_names_.append(member_name) - # get redirect in place before adding to _member_map_ - # but check for other instances in parent classes first - descriptor = None + # if necessary, get redirect in place and then add it to _member_map_ + found_descriptor = None for base in enum_class.__mro__[1:]: descriptor = base.__dict__.get(member_name) if descriptor is not None: if isinstance(descriptor, (property, DynamicClassAttribute)): + found_descriptor = descriptor break - redirect = property() - redirect.member = enum_member - redirect.__set_name__(enum_class, member_name) - if descriptor: - redirect.fget = getattr(descriptor, 'fget', None) - redirect.fset = getattr(descriptor, 'fset', None) - redirect.fdel = getattr(descriptor, 'fdel', None) - setattr(enum_class, member_name, redirect) + elif ( + hasattr(descriptor, 'fget') and + hasattr(descriptor, 'fset') and + hasattr(descriptor, 'fdel') + ): + found_descriptor = descriptor + continue + if found_descriptor: + redirect = property() + redirect.member = enum_member + redirect.__set_name__(enum_class, member_name) + # earlier descriptor found; copy fget, fset, fdel to this one. + redirect.fget = found_descriptor.fget + redirect.fset = found_descriptor.fset + redirect.fdel = found_descriptor.fdel + setattr(enum_class, member_name, redirect) + else: + setattr(enum_class, member_name, enum_member) # now add to _member_map_ (even aliases) enum_class._member_map_[member_name] = enum_member try: diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index ee5280601be1..e4151bf9e6d9 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -2686,28 +2686,15 @@ class Private(Enum): self.assertEqual(Private._Private__corporal, 'Radar') self.assertEqual(Private._Private__major_, 'Hoolihan') - @unittest.skipIf( - python_version <= (3, 13), - 'member.member access currently deprecated', - ) - def test_exception_for_member_from_member_access(self): - with self.assertRaisesRegex(AttributeError, " member has no attribute .NO."): - class Di(Enum): - YES = 1 - NO = 0 - nope = Di.YES.NO - - @unittest.skipIf( - python_version > (3, 13), - 'member.member access now raises', - ) - def test_warning_for_member_from_member_access(self): - with self.assertWarnsRegex(DeprecationWarning, '`member.member` access .* is deprecated and will be removed in 3.14'): - class Di(Enum): - YES = 1 - NO = 0 - warn = Di.YES.NO + def test_member_from_member_access(self): + class Di(Enum): + YES = 1 + NO = 0 + name = 3 + warn = Di.YES.NO self.assertIs(warn, Di.NO) + self.assertIs(Di.name, Di['name']) + self.assertEqual(Di.name.name, 'name') def test_dynamic_members_with_static_methods(self): # diff --git a/Misc/NEWS.d/next/Library/2023-04-04-12-43-38.gh-issue-93910.jurMzv.rst b/Misc/NEWS.d/next/Library/2023-04-04-12-43-38.gh-issue-93910.jurMzv.rst new file mode 100644 index 000000000000..783aefae0770 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-04-12-43-38.gh-issue-93910.jurMzv.rst @@ -0,0 +1 @@ +Remove deprecation of enum ``memmber.member`` access. From webhook-mailer at python.org Wed Apr 5 20:42:09 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Thu, 06 Apr 2023 00:42:09 -0000 Subject: [Python-checkins] gh-101659: Add _Py_AtExit() (gh-103298) Message-ID: https://github.com/python/cpython/commit/03089fdccc7dbe3f69227fbd570df92278371e7f commit: 03089fdccc7dbe3f69227fbd570df92278371e7f branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-04-05T18:42:02-06:00 summary: gh-101659: Add _Py_AtExit() (gh-103298) The function is like Py_AtExit() but for a single interpreter. This is a companion to the atexit module's register() function, taking a C callback instead of a Python one. We also update the _xxinterpchannels module to use _Py_AtExit(), which is the motivating case. (This is inspired by pain points felt while working on gh-101660.) files: A Include/internal/pycore_atexit.h M Include/cpython/pylifecycle.h M Include/internal/pycore_interp.h M Include/internal/pycore_runtime.h M Lib/test/test__xxinterpchannels.py M Makefile.pre.in M Modules/_testcapimodule.c M Modules/_xxinterpchannelsmodule.c M Modules/_xxsubinterpretersmodule.c M Modules/atexitmodule.c M PCbuild/pythoncore.vcxproj M PCbuild/pythoncore.vcxproj.filters M Python/pylifecycle.c diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h index 821b169d7a17..79d55711319e 100644 --- a/Include/cpython/pylifecycle.h +++ b/Include/cpython/pylifecycle.h @@ -65,3 +65,7 @@ PyAPI_FUNC(char *) _Py_SetLocaleFromEnv(int category); PyAPI_FUNC(PyStatus) _Py_NewInterpreterFromConfig( PyThreadState **tstate_p, const _PyInterpreterConfig *config); + +typedef void (*atexit_datacallbackfunc)(void *); +PyAPI_FUNC(int) _Py_AtExit( + PyInterpreterState *, atexit_datacallbackfunc, void *); diff --git a/Include/internal/pycore_atexit.h b/Include/internal/pycore_atexit.h new file mode 100644 index 000000000000..b4663b396852 --- /dev/null +++ b/Include/internal/pycore_atexit.h @@ -0,0 +1,56 @@ +#ifndef Py_INTERNAL_ATEXIT_H +#define Py_INTERNAL_ATEXIT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + + +//############### +// runtime atexit + +typedef void (*atexit_callbackfunc)(void); + +struct _atexit_runtime_state { +#define NEXITFUNCS 32 + atexit_callbackfunc callbacks[NEXITFUNCS]; + int ncallbacks; +}; + + +//################### +// interpreter atexit + +struct atexit_callback; +typedef struct atexit_callback { + atexit_datacallbackfunc func; + void *data; + struct atexit_callback *next; +} atexit_callback; + +typedef struct { + PyObject *func; + PyObject *args; + PyObject *kwargs; +} atexit_py_callback; + +struct atexit_state { + atexit_callback *ll_callbacks; + atexit_callback *last_ll_callback; + + // XXX The rest of the state could be moved to the atexit module state + // and a low-level callback added for it during module exec. + // For the moment we leave it here. + atexit_py_callback **callbacks; + int ncallbacks; + int callback_len; +}; + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_ATEXIT_H */ diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 1f2c0db2eb5f..d64a68cd2da5 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -10,8 +10,9 @@ extern "C" { #include -#include "pycore_atomic.h" // _Py_atomic_address #include "pycore_ast_state.h" // struct ast_state +#include "pycore_atexit.h" // struct atexit_state +#include "pycore_atomic.h" // _Py_atomic_address #include "pycore_ceval_state.h" // struct _ceval_state #include "pycore_code.h" // struct callable_cache #include "pycore_context.h" // struct _Py_context_state @@ -32,20 +33,6 @@ extern "C" { #include "pycore_warnings.h" // struct _warnings_runtime_state -// atexit state -typedef struct { - PyObject *func; - PyObject *args; - PyObject *kwargs; -} atexit_callback; - -struct atexit_state { - atexit_callback **callbacks; - int ncallbacks; - int callback_len; -}; - - struct _Py_long_state { int max_str_digits; }; diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index 8877b282bc38..3ebe49926edd 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -8,6 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_atexit.h" // struct atexit_runtime_state #include "pycore_atomic.h" /* _Py_atomic_address */ #include "pycore_ceval_state.h" // struct _ceval_runtime_state #include "pycore_floatobject.h" // struct _Py_float_runtime_state @@ -131,9 +132,7 @@ typedef struct pyruntimestate { struct _parser_runtime_state parser; -#define NEXITFUNCS 32 - void (*exitfuncs[NEXITFUNCS])(void); - int nexitfuncs; + struct _atexit_runtime_state atexit; struct _import_runtime_state imports; struct _ceval_runtime_state ceval; diff --git a/Lib/test/test__xxinterpchannels.py b/Lib/test/test__xxinterpchannels.py index 69bda89a1688..b65281106f66 100644 --- a/Lib/test/test__xxinterpchannels.py +++ b/Lib/test/test__xxinterpchannels.py @@ -550,6 +550,7 @@ def test_channel_list_interpreters_closed_send_end(self): import _xxinterpchannels as _channels _channels.close({cid}, force=True) """)) + return # Both ends should raise an error. with self.assertRaises(channels.ChannelClosedError): channels.list_interpreters(cid, send=True) @@ -673,17 +674,34 @@ def test_recv_default(self): self.assertIs(obj6, default) def test_recv_sending_interp_destroyed(self): - cid = channels.create() - interp = interpreters.create() - interpreters.run_string(interp, dedent(f""" - import _xxinterpchannels as _channels - _channels.send({cid}, b'spam') - """)) - interpreters.destroy(interp) - - with self.assertRaisesRegex(RuntimeError, - 'unrecognized interpreter ID'): - channels.recv(cid) + with self.subTest('closed'): + cid1 = channels.create() + interp = interpreters.create() + interpreters.run_string(interp, dedent(f""" + import _xxinterpchannels as _channels + _channels.send({cid1}, b'spam') + """)) + interpreters.destroy(interp) + + with self.assertRaisesRegex(RuntimeError, + f'channel {cid1} is closed'): + channels.recv(cid1) + del cid1 + with self.subTest('still open'): + cid2 = channels.create() + interp = interpreters.create() + interpreters.run_string(interp, dedent(f""" + import _xxinterpchannels as _channels + _channels.send({cid2}, b'spam') + """)) + channels.send(cid2, b'eggs') + interpreters.destroy(interp) + + channels.recv(cid2) + with self.assertRaisesRegex(RuntimeError, + f'channel {cid2} is empty'): + channels.recv(cid2) + del cid2 def test_allowed_types(self): cid = channels.create() diff --git a/Makefile.pre.in b/Makefile.pre.in index 9fdbd8db19bb..1c1bddcad824 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1660,6 +1660,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_asdl.h \ $(srcdir)/Include/internal/pycore_ast.h \ $(srcdir)/Include/internal/pycore_ast_state.h \ + $(srcdir)/Include/internal/pycore_atexit.h \ $(srcdir)/Include/internal/pycore_atomic.h \ $(srcdir)/Include/internal/pycore_atomic_funcs.h \ $(srcdir)/Include/internal/pycore_bitutils.h \ diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 3d9a2aeeb7cf..557a6d46ed46 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3381,6 +3381,37 @@ test_gc_visit_objects_exit_early(PyObject *Py_UNUSED(self), } +struct atexit_data { + int called; +}; + +static void +callback(void *data) +{ + ((struct atexit_data *)data)->called += 1; +} + +static PyObject * +test_atexit(PyObject *self, PyObject *Py_UNUSED(args)) +{ + PyThreadState *oldts = PyThreadState_Swap(NULL); + PyThreadState *tstate = Py_NewInterpreter(); + + struct atexit_data data = {0}; + int res = _Py_AtExit(tstate->interp, callback, (void *)&data); + Py_EndInterpreter(tstate); + PyThreadState_Swap(oldts); + if (res < 0) { + return NULL; + } + if (data.called == 0) { + PyErr_SetString(PyExc_RuntimeError, "atexit callback not called"); + return NULL; + } + Py_RETURN_NONE; +} + + static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *); static PyMethodDef TestMethods[] = { @@ -3525,6 +3556,7 @@ static PyMethodDef TestMethods[] = { {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL}, {"test_gc_visit_objects_basic", test_gc_visit_objects_basic, METH_NOARGS, NULL}, {"test_gc_visit_objects_exit_early", test_gc_visit_objects_exit_early, METH_NOARGS, NULL}, + {"test_atexit", test_atexit, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_xxinterpchannelsmodule.c b/Modules/_xxinterpchannelsmodule.c index ef1cdcab9522..13b005eaef98 100644 --- a/Modules/_xxinterpchannelsmodule.c +++ b/Modules/_xxinterpchannelsmodule.c @@ -174,19 +174,7 @@ _release_xid_data(_PyCrossInterpreterData *data, int ignoreexc) } int res = _PyCrossInterpreterData_Release(data); if (res < 0) { - // XXX Fix this! - /* The owning interpreter is already destroyed. - * Ideally, this shouldn't ever happen. When an interpreter is - * about to be destroyed, we should clear out all of its objects - * from every channel associated with that interpreter. - * For now we hack around that to resolve refleaks, by decref'ing - * the released object here, even if its the wrong interpreter. - * The owning interpreter has already been destroyed - * so we should be okay, especially since the currently - * shareable types are all very basic, with no GC. - * That said, it becomes much messier once interpreters - * no longer share a GIL, so this needs to be fixed before then. */ - _PyCrossInterpreterData_Clear(NULL, data); + /* The owning interpreter is already destroyed. */ if (ignoreexc) { // XXX Emit a warning? PyErr_Clear(); @@ -489,6 +477,30 @@ _channelqueue_get(_channelqueue *queue) return _channelitem_popped(item); } +static void +_channelqueue_drop_interpreter(_channelqueue *queue, int64_t interp) +{ + _channelitem *prev = NULL; + _channelitem *next = queue->first; + while (next != NULL) { + _channelitem *item = next; + next = item->next; + if (item->data->interp == interp) { + if (prev == NULL) { + queue->first = item->next; + } + else { + prev->next = item->next; + } + _channelitem_free(item); + queue->count -= 1; + } + else { + prev = item; + } + } +} + /* channel-interpreter associations */ struct _channelend; @@ -693,6 +705,20 @@ _channelends_close_interpreter(_channelends *ends, int64_t interp, int which) return 0; } +static void +_channelends_drop_interpreter(_channelends *ends, int64_t interp) +{ + _channelend *end; + end = _channelend_find(ends->send, interp, NULL); + if (end != NULL) { + _channelends_close_end(ends, end, 1); + } + end = _channelend_find(ends->recv, interp, NULL); + if (end != NULL) { + _channelends_close_end(ends, end, 0); + } +} + static void _channelends_close_all(_channelends *ends, int which, int force) { @@ -841,6 +867,18 @@ _channel_close_interpreter(_PyChannelState *chan, int64_t interp, int end) return res; } +static void +_channel_drop_interpreter(_PyChannelState *chan, int64_t interp) +{ + PyThread_acquire_lock(chan->mutex, WAIT_LOCK); + + _channelqueue_drop_interpreter(chan->queue, interp); + _channelends_drop_interpreter(chan->ends, interp); + chan->open = _channelends_is_open(chan->ends); + + PyThread_release_lock(chan->mutex); +} + static int _channel_close_all(_PyChannelState *chan, int end, int force) { @@ -1213,6 +1251,21 @@ _channels_list_all(_channels *channels, int64_t *count) return cids; } +static void +_channels_drop_interpreter(_channels *channels, int64_t interp) +{ + PyThread_acquire_lock(channels->mutex, WAIT_LOCK); + + _channelref *ref = channels->head; + for (; ref != NULL; ref = ref->next) { + if (ref->chan != NULL) { + _channel_drop_interpreter(ref->chan, interp); + } + } + + PyThread_release_lock(channels->mutex); +} + /* support for closing non-empty channels */ struct _channel_closing { @@ -1932,6 +1985,19 @@ _global_channels(void) { } +static void +clear_interpreter(void *data) +{ + if (_globals.module_count == 0) { + return; + } + PyInterpreterState *interp = (PyInterpreterState *)data; + assert(interp == _get_current_interp()); + int64_t id = PyInterpreterState_GetID(interp); + _channels_drop_interpreter(&_globals.channels, id); +} + + static PyObject * channel_create(PyObject *self, PyObject *Py_UNUSED(ignored)) { @@ -2339,6 +2405,10 @@ module_exec(PyObject *mod) goto error; } + // Make sure chnnels drop objects owned by this interpreter + PyInterpreterState *interp = _get_current_interp(); + _Py_AtExit(interp, clear_interpreter, (void *)interp); + return 0; error: diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 11164676c4d1..884fb0d31f2b 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -67,16 +67,7 @@ _release_xid_data(_PyCrossInterpreterData *data, int ignoreexc) } int res = _PyCrossInterpreterData_Release(data); if (res < 0) { - // XXX Fix this! - /* The owning interpreter is already destroyed. - * Ideally, this shouldn't ever happen. (It's highly unlikely.) - * For now we hack around that to resolve refleaks, by decref'ing - * the released object here, even if its the wrong interpreter. - * The owning interpreter has already been destroyed - * so we should be okay, especially since the currently - * shareable types are all very basic, with no GC. - * That said, it becomes much messier once interpreters - * no longer share a GIL, so this needs to be fixed before then. */ + /* The owning interpreter is already destroyed. */ _PyCrossInterpreterData_Clear(NULL, data); if (ignoreexc) { // XXX Emit a warning? diff --git a/Modules/atexitmodule.c b/Modules/atexitmodule.c index a1c511e09d70..47afd7f07510 100644 --- a/Modules/atexitmodule.c +++ b/Modules/atexitmodule.c @@ -7,6 +7,7 @@ */ #include "Python.h" +#include "pycore_atexit.h" #include "pycore_initconfig.h" // _PyStatus_NO_MEMORY #include "pycore_interp.h" // PyInterpreterState.atexit #include "pycore_pystate.h" // _PyInterpreterState_GET @@ -22,10 +23,36 @@ get_atexit_state(void) } +int +_Py_AtExit(PyInterpreterState *interp, + atexit_datacallbackfunc func, void *data) +{ + assert(interp == _PyInterpreterState_GET()); + atexit_callback *callback = PyMem_Malloc(sizeof(atexit_callback)); + if (callback == NULL) { + PyErr_NoMemory(); + return -1; + } + callback->func = func; + callback->data = data; + callback->next = NULL; + + struct atexit_state *state = &interp->atexit; + if (state->ll_callbacks == NULL) { + state->ll_callbacks = callback; + state->last_ll_callback = callback; + } + else { + state->last_ll_callback->next = callback; + } + return 0; +} + + static void atexit_delete_cb(struct atexit_state *state, int i) { - atexit_callback *cb = state->callbacks[i]; + atexit_py_callback *cb = state->callbacks[i]; state->callbacks[i] = NULL; Py_DECREF(cb->func); @@ -39,7 +66,7 @@ atexit_delete_cb(struct atexit_state *state, int i) static void atexit_cleanup(struct atexit_state *state) { - atexit_callback *cb; + atexit_py_callback *cb; for (int i = 0; i < state->ncallbacks; i++) { cb = state->callbacks[i]; if (cb == NULL) @@ -60,7 +87,7 @@ _PyAtExit_Init(PyInterpreterState *interp) state->callback_len = 32; state->ncallbacks = 0; - state->callbacks = PyMem_New(atexit_callback*, state->callback_len); + state->callbacks = PyMem_New(atexit_py_callback*, state->callback_len); if (state->callbacks == NULL) { return _PyStatus_NO_MEMORY(); } @@ -75,6 +102,18 @@ _PyAtExit_Fini(PyInterpreterState *interp) atexit_cleanup(state); PyMem_Free(state->callbacks); state->callbacks = NULL; + + atexit_callback *next = state->ll_callbacks; + state->ll_callbacks = NULL; + while (next != NULL) { + atexit_callback *callback = next; + next = callback->next; + atexit_datacallbackfunc exitfunc = callback->func; + void *data = callback->data; + // It was allocated in _PyAtExit_AddCallback(). + PyMem_Free(callback); + exitfunc(data); + } } @@ -88,7 +127,7 @@ atexit_callfuncs(struct atexit_state *state) } for (int i = state->ncallbacks - 1; i >= 0; i--) { - atexit_callback *cb = state->callbacks[i]; + atexit_py_callback *cb = state->callbacks[i]; if (cb == NULL) { continue; } @@ -152,17 +191,17 @@ atexit_register(PyObject *module, PyObject *args, PyObject *kwargs) struct atexit_state *state = get_atexit_state(); if (state->ncallbacks >= state->callback_len) { - atexit_callback **r; + atexit_py_callback **r; state->callback_len += 16; - size_t size = sizeof(atexit_callback*) * (size_t)state->callback_len; - r = (atexit_callback**)PyMem_Realloc(state->callbacks, size); + size_t size = sizeof(atexit_py_callback*) * (size_t)state->callback_len; + r = (atexit_py_callback**)PyMem_Realloc(state->callbacks, size); if (r == NULL) { return PyErr_NoMemory(); } state->callbacks = r; } - atexit_callback *callback = PyMem_Malloc(sizeof(atexit_callback)); + atexit_py_callback *callback = PyMem_Malloc(sizeof(atexit_py_callback)); if (callback == NULL) { return PyErr_NoMemory(); } @@ -233,7 +272,7 @@ atexit_unregister(PyObject *module, PyObject *func) struct atexit_state *state = get_atexit_state(); for (int i = 0; i < state->ncallbacks; i++) { - atexit_callback *cb = state->callbacks[i]; + atexit_py_callback *cb = state->callbacks[i]; if (cb == NULL) { continue; } diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 8fab60033416..29f32db579fa 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -197,6 +197,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 6c5d8dd89f5b..6a622fd93930 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -498,6 +498,9 @@ Include\internal + + Include\internal + Include\internal diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 8110d94ba175..d6627bc6b7e8 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2937,23 +2937,23 @@ wait_for_thread_shutdown(PyThreadState *tstate) Py_DECREF(threading); } -#define NEXITFUNCS 32 int Py_AtExit(void (*func)(void)) { - if (_PyRuntime.nexitfuncs >= NEXITFUNCS) + if (_PyRuntime.atexit.ncallbacks >= NEXITFUNCS) return -1; - _PyRuntime.exitfuncs[_PyRuntime.nexitfuncs++] = func; + _PyRuntime.atexit.callbacks[_PyRuntime.atexit.ncallbacks++] = func; return 0; } static void call_ll_exitfuncs(_PyRuntimeState *runtime) { - while (runtime->nexitfuncs > 0) { + struct _atexit_runtime_state *state = &runtime->atexit; + while (state->ncallbacks > 0) { /* pop last function from the list */ - runtime->nexitfuncs--; - void (*exitfunc)(void) = runtime->exitfuncs[runtime->nexitfuncs]; - runtime->exitfuncs[runtime->nexitfuncs] = NULL; + state->ncallbacks--; + atexit_callbackfunc exitfunc = state->callbacks[state->ncallbacks]; + state->callbacks[state->ncallbacks] = NULL; exitfunc(); } From webhook-mailer at python.org Wed Apr 5 23:42:21 2023 From: webhook-mailer at python.org (ned-deily) Date: Thu, 06 Apr 2023 03:42:21 -0000 Subject: [Python-checkins] gh-103207: Fix Welcome formatting issues when macOS Installer is run in dark mode. (GH-103303) Message-ID: https://github.com/python/cpython/commit/6e3ee049ace60beb97784f10099ae399efd83bac commit: 6e3ee049ace60beb97784f10099ae399efd83bac branch: main author: Ned Deily committer: ned-deily date: 2023-04-05T23:42:14-04:00 summary: gh-103207: Fix Welcome formatting issues when macOS Installer is run in dark mode. (GH-103303) files: M Mac/BuildScript/resources/Welcome.rtf diff --git a/Mac/BuildScript/resources/Welcome.rtf b/Mac/BuildScript/resources/Welcome.rtf index efdcb12f849b..1f109ee9f13e 100644 --- a/Mac/BuildScript/resources/Welcome.rtf +++ b/Mac/BuildScript/resources/Welcome.rtf @@ -1,9 +1,9 @@ {\rtf1\ansi\ansicpg1252\cocoartf2708 \cocoascreenfonts1\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;\f2\fmodern\fcharset0 CourierNewPSMT; -\f3\fnil\fcharset0 HelveticaNeue;\f4\fnil\fcharset0 HelveticaNeue-Bold;} -{\colortbl;\red255\green255\blue255;\red24\green26\blue30;\red255\green255\blue255;} -{\*\expandedcolortbl;;\cssrgb\c12157\c13725\c15686;\cssrgb\c100000\c100000\c100000;} -\margl1440\margr1440\vieww12820\viewh10620\viewkind0 +} +{\colortbl;\red255\green255\blue255;} +{\*\expandedcolortbl;;} +\margl1440\margr1440\vieww12200\viewh10880\viewkind0 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\partightenfactor0 \f0\fs24 \cf0 This package will install @@ -26,32 +26,25 @@ At the end of this install, click on \ \f1\b macOS 13 Ventura users -\f0\b0 : due to an issue with macOS +\f0\b0 : Due to an issue with the macOS \f1\b Installer -\f0\b0 app, installation of some -\f3 \cf2 \cb3 \expnd0\expndtw0\kerning0 -third-party -\f0 \cf0 \cb1 \kerning1\expnd0\expndtw0 packages including this Python package may fail with a vague -\f4\b \cf2 \cb3 \expnd0\expndtw0\kerning0 -\'93The installer encountered an error\'94 -\f3\b0 message if the -\f4\b Installer -\f3\b0 app does not have permission to access the folder containing the downloaded installer file, typically in the -\f4\b Downloads -\f3\b0 folder. Go to -\f4\b System Settings -\f3\b0 -> -\f4\b Privacy & Security -\f3\b0 -> -\f4\b Files and Folders -\f3\b0 , then click the mark in front of -\f4\b Installer -\f3\b0 to expand, and enable -\f4\b Downloads Folder -\f0\b0 \cf0 \cb1 \kerning1\expnd0\expndtw0 by moving the toggle to the right -\f3 \cf2 \cb3 \expnd0\expndtw0\kerning0 -. See {\field{\*\fldinst{HYPERLINK "https://github.com/python/cpython/issues/103207"}}{\fldrslt https://github.com/python/cpython/issues/103207}} for up-to-date information on this issue. -\f0 \cf0 \cb1 \kerning1\expnd0\expndtw0 \ +\f0\b0 app, installation of some third-party packages including this Python package may fail with a vague +\f1\b "The installer encountered an error" +\f0\b0 message if the +\f1\b Installer +\f0\b0 app does not have permission to access the folder containing the downloaded installer file, typically in the +\f1\b Downloads +\f0\b0 folder. Go to +\f1\b System Settings +\f0\b0 -> +\f1\b Privacy & Security +\f0\b0 -> +\f1\b Files and Folders +\f0\b0 , then click the mark in front of +\f1\b Installer +\f0\b0 to expand, and enable +\f1\b Downloads Folder +\f0\b0 by moving the toggle to the right. See {\field{\*\fldinst{HYPERLINK "https://github.com/python/cpython/issues/103207"}}{\fldrslt https://github.com/python/cpython/issues/103207}} for up-to-date information on this issue.\ \ \f1\b NOTE: From webhook-mailer at python.org Wed Apr 5 23:43:26 2023 From: webhook-mailer at python.org (ned-deily) Date: Thu, 06 Apr 2023 03:43:26 -0000 Subject: [Python-checkins] [3.11] gh-103207: Fix Welcome formatting issues when macOS Installer is run in dark mode. (GH-103302) Message-ID: https://github.com/python/cpython/commit/0291397c5766cf6c0d8f280332fecb207824a75d commit: 0291397c5766cf6c0d8f280332fecb207824a75d branch: 3.11 author: Ned Deily committer: ned-deily date: 2023-04-05T23:43:19-04:00 summary: [3.11] gh-103207: Fix Welcome formatting issues when macOS Installer is run in dark mode. (GH-103302) files: M Mac/BuildScript/resources/Welcome.rtf diff --git a/Mac/BuildScript/resources/Welcome.rtf b/Mac/BuildScript/resources/Welcome.rtf index 9adf4173ff16..6f7cff442e5d 100644 --- a/Mac/BuildScript/resources/Welcome.rtf +++ b/Mac/BuildScript/resources/Welcome.rtf @@ -1,8 +1,8 @@ {\rtf1\ansi\ansicpg1252\cocoartf2708 \cocoascreenfonts1\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;\f2\fmodern\fcharset0 CourierNewPSMT; -\f3\fnil\fcharset0 HelveticaNeue;\f4\fnil\fcharset0 HelveticaNeue-Bold;} -{\colortbl;\red255\green255\blue255;\red24\green26\blue30;\red255\green255\blue255;} -{\*\expandedcolortbl;;\cssrgb\c12157\c13725\c15686;\cssrgb\c100000\c100000\c100000;} +} +{\colortbl;\red255\green255\blue255;} +{\*\expandedcolortbl;;} \margl1440\margr1440\vieww12200\viewh10880\viewkind0 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\partightenfactor0 @@ -12,9 +12,8 @@ \f1\b macOS $MACOSX_DEPLOYMENT_TARGET \f0\b0 .\ \ -\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\partightenfactor0 -\f1\b \cf0 Python for macOS +\f1\b Python for macOS \f0\b0 consists of the {\field{\*\fldinst{HYPERLINK "https://www.python.org"}}{\fldrslt Python}} programming language interpreter and its batteries-included standard library to allow easy access to macOS features. It also includes the Python integrated development environment, \f1\b IDLE \f0\b0 . You can also use the included @@ -27,30 +26,24 @@ At the end of this install, click on \ \f1\b macOS 13 Ventura users -\f0\b0 : due to an issue with macOS +\f0\b0 : Due to an issue with the macOS +\f1\b Installer +\f0\b0 app, installation of some third-party packages including this Python package may fail with a vague +\f1\b "The installer encountered an error" +\f0\b0 message if the \f1\b Installer -\f0\b0 app, installation of some -\f3 \cf2 \cb3 \expnd0\expndtw0\kerning0 -third-party -\f0 \cf0 \cb1 \kerning1\expnd0\expndtw0 packages including this Python package may fail with a vague -\f4\b \cf2 \cb3 \expnd0\expndtw0\kerning0 -\'93The installer encountered an error\'94 -\f3\b0 \cf2 message if the -\f4\b \cf2 Installer -\f3\b0 \cf2 app does not have permission to access the folder containing the downloaded installer file, typically in the -\f4\b \cf2 Downloads -\f3\b0 \cf2 folder. Go to -\f4\b \cf2 System Settings -\f3\b0 \cf2 -> -\f4\b \cf2 Privacy & Security -\f3\b0 \cf2 -> -\f4\b \cf2 Files and Folders -\f3\b0 \cf2 , then click the mark in front of -\f4\b \cf2 Installer -\f3\b0 \cf2 to expand, and enable -\f4\b \cf2 Downloads Folder -\f0\b0 \cf0 \cb1 \kerning1\expnd0\expndtw0 by moving the toggle to the right -\f3 \cf2 \cb3 \expnd0\expndtw0\kerning0 -. See {\field{\*\fldinst{HYPERLINK "https://github.com/python/cpython/issues/103207"}}{\fldrslt https://github.com/python/cpython/issues/103207}} for up-to-date information on this issue. -\f0 \cf0 \cb1 \kerning1\expnd0\expndtw0 \ +\f0\b0 app does not have permission to access the folder containing the downloaded installer file, typically in the +\f1\b Downloads +\f0\b0 folder. Go to +\f1\b System Settings +\f0\b0 -> +\f1\b Privacy & Security +\f0\b0 -> +\f1\b Files and Folders +\f0\b0 , then click the mark in front of +\f1\b Installer +\f0\b0 to expand, and enable +\f1\b Downloads Folder +\f0\b0 by moving the toggle to the right. See {\field{\*\fldinst{HYPERLINK "https://github.com/python/cpython/issues/103207"}}{\fldrslt https://github.com/python/cpython/issues/103207}} for up-to-date information on this issue.\ +\ } \ No newline at end of file From webhook-mailer at python.org Wed Apr 5 23:44:26 2023 From: webhook-mailer at python.org (ned-deily) Date: Thu, 06 Apr 2023 03:44:26 -0000 Subject: [Python-checkins] [3.10] gh-103207: Fix Welcome formatting issues when macOS Installer is run in dark mode. (GH-103304) Message-ID: https://github.com/python/cpython/commit/4075e0166fcae0eef5e3abe1a97b3c227ce6861c commit: 4075e0166fcae0eef5e3abe1a97b3c227ce6861c branch: 3.10 author: Ned Deily committer: ned-deily date: 2023-04-05T23:44:19-04:00 summary: [3.10] gh-103207: Fix Welcome formatting issues when macOS Installer is run in dark mode. (GH-103304) files: M Mac/BuildScript/resources/Welcome.rtf diff --git a/Mac/BuildScript/resources/Welcome.rtf b/Mac/BuildScript/resources/Welcome.rtf index 1be87b64e1fd..6f7cff442e5d 100644 --- a/Mac/BuildScript/resources/Welcome.rtf +++ b/Mac/BuildScript/resources/Welcome.rtf @@ -1,8 +1,8 @@ {\rtf1\ansi\ansicpg1252\cocoartf2708 \cocoascreenfonts1\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;\f2\fmodern\fcharset0 CourierNewPSMT; -\f3\fnil\fcharset0 HelveticaNeue;\f4\fnil\fcharset0 HelveticaNeue-Bold;} -{\colortbl;\red255\green255\blue255;\red24\green26\blue30;\red255\green255\blue255;} -{\*\expandedcolortbl;;\cssrgb\c12157\c13725\c15686;\cssrgb\c100000\c100000\c100000;} +} +{\colortbl;\red255\green255\blue255;} +{\*\expandedcolortbl;;} \margl1440\margr1440\vieww12200\viewh10880\viewkind0 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\partightenfactor0 @@ -12,9 +12,8 @@ \f1\b macOS $MACOSX_DEPLOYMENT_TARGET \f0\b0 .\ \ -\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\partightenfactor0 -\f1\b \cf0 Python for macOS +\f1\b Python for macOS \f0\b0 consists of the {\field{\*\fldinst{HYPERLINK "https://www.python.org"}}{\fldrslt Python}} programming language interpreter and its batteries-included standard library to allow easy access to macOS features. It also includes the Python integrated development environment, \f1\b IDLE \f0\b0 . You can also use the included @@ -27,31 +26,24 @@ At the end of this install, click on \ \f1\b macOS 13 Ventura users -\f0\b0 : due to an issue with macOS +\f0\b0 : Due to an issue with the macOS +\f1\b Installer +\f0\b0 app, installation of some third-party packages including this Python package may fail with a vague +\f1\b "The installer encountered an error" +\f0\b0 message if the +\f1\b Installer +\f0\b0 app does not have permission to access the folder containing the downloaded installer file, typically in the +\f1\b Downloads +\f0\b0 folder. Go to +\f1\b System Settings +\f0\b0 -> +\f1\b Privacy & Security +\f0\b0 -> +\f1\b Files and Folders +\f0\b0 , then click the mark in front of \f1\b Installer -\f0\b0 app, installation of some -\f3 \cf2 \cb3 \expnd0\expndtw0\kerning0 -third-party -\f0 \cf0 \cb1 \kerning1\expnd0\expndtw0 packages including this Python package may fail with a vague -\f4\b \cf2 \cb3 \expnd0\expndtw0\kerning0 -\'93The installer encountered an error\'94 -\f3\b0 \cf2 message if the -\f4\b \cf2 Installer -\f3\b0 \cf2 app does not have permission to access the folder containing the downloaded installer file, typically in the -\f4\b \cf2 Downloads -\f3\b0 \cf2 folder. Go to -\f4\b \cf2 System Settings -\f3\b0 \cf2 -> -\f4\b \cf2 Privacy & Security -\f3\b0 \cf2 -> -\f4\b \cf2 Files and Folders -\f3\b0 \cf2 , then click the mark in front of -\f4\b \cf2 Installer -\f3\b0 \cf2 to expand, and enable -\f4\b \cf2 Downloads Folder -\f0\b0 \cf0 \cb1 \kerning1\expnd0\expndtw0 by moving the toggle to the right -\f3 \cf2 \cb3 \expnd0\expndtw0\kerning0 -. See {\field{\*\fldinst{HYPERLINK "https://github.com/python/cpython/issues/103207"}}{\fldrslt https://github.com/python/cpython/issues/103207}} for up-to-date information on this issue. -\f0 \cf0 \cb1 \kerning1\expnd0\expndtw0 \ +\f0\b0 to expand, and enable +\f1\b Downloads Folder +\f0\b0 by moving the toggle to the right. See {\field{\*\fldinst{HYPERLINK "https://github.com/python/cpython/issues/103207"}}{\fldrslt https://github.com/python/cpython/issues/103207}} for up-to-date information on this issue.\ \ } \ No newline at end of file From webhook-mailer at python.org Thu Apr 6 00:29:22 2023 From: webhook-mailer at python.org (ethanfurman) Date: Thu, 06 Apr 2023 04:29:22 -0000 Subject: [Python-checkins] [3.11] gh-93910: [Enum] remove member.member deprecation (GH-103236) (GH-103299) Message-ID: https://github.com/python/cpython/commit/58e330ac9cae32f9f44bab24448766085fd29ae6 commit: 58e330ac9cae32f9f44bab24448766085fd29ae6 branch: 3.11 author: Ethan Furman committer: ethanfurman date: 2023-04-05T21:29:14-07:00 summary: [3.11] gh-93910: [Enum] remove member.member deprecation (GH-103236) (GH-103299) i.e. Color.RED.BLUE is now officially supported.. (cherry picked from commit 4ec8dd10bd4682793559c4eccbcf6ae00688c4c3) Co-authored-by: Ethan Furman files: A Misc/NEWS.d/next/Library/2023-04-04-12-43-38.gh-issue-93910.jurMzv.rst M Doc/howto/enum.rst M Lib/enum.py M Lib/test/test_enum.py diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst index f2a10c03fa88..32310692fe56 100644 --- a/Doc/howto/enum.rst +++ b/Doc/howto/enum.rst @@ -960,23 +960,11 @@ but remain normal attributes. """""""""""""""""""" Enum members are instances of their enum class, and are normally accessed as -``EnumClass.member``. In Python versions ``3.5`` to ``3.10`` you could access -members from other members -- this practice was discouraged, and in ``3.11`` -:class:`Enum` returns to not allowing it:: - - >>> class FieldTypes(Enum): - ... name = 0 - ... value = 1 - ... size = 2 - ... - >>> FieldTypes.value.size - Traceback (most recent call last): - ... - AttributeError: member has no attribute 'size' - +``EnumClass.member``. In certain situations, such as writing custom enum +behavior, being able to access one member directly from another is useful, +and is supported. .. versionchanged:: 3.5 -.. versionchanged:: 3.11 Creating members that are mixed with other data types diff --git a/Lib/enum.py b/Lib/enum.py index 13da287b34aa..84ae339d0d40 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -199,9 +199,13 @@ def __get__(self, instance, ownerclass=None): ) else: if self.fget is None: - raise AttributeError( - '%r member has no attribute %r' % (ownerclass, self.name) - ) + # look for a member by this name. + try: + return ownerclass._member_map_[self.name] + except KeyError: + raise AttributeError( + '%r has no attribute %r' % (ownerclass, self.name) + ) from None else: return self.fget(instance) @@ -298,29 +302,29 @@ def __set_name__(self, enum_class, member_name): ): # no other instances found, record this member in _member_names_ enum_class._member_names_.append(member_name) - # get redirect in place before adding to _member_map_ - # but check for other instances in parent classes first - need_override = False - descriptor = None + # if necessary, get redirect in place and then add it to _member_map_ + found_descriptor = None for base in enum_class.__mro__[1:]: descriptor = base.__dict__.get(member_name) if descriptor is not None: if isinstance(descriptor, (property, DynamicClassAttribute)): + found_descriptor = descriptor break - else: - need_override = True - # keep looking for an enum.property - if descriptor and not need_override: - # previous enum.property found, no further action needed - pass - elif descriptor and need_override: + elif ( + hasattr(descriptor, 'fget') and + hasattr(descriptor, 'fset') and + hasattr(descriptor, 'fdel') + ): + found_descriptor = descriptor + continue + if found_descriptor: redirect = property() + redirect.member = enum_member redirect.__set_name__(enum_class, member_name) - # Previous enum.property found, but some other inherited attribute - # is in the way; copy fget, fset, fdel to this one. - redirect.fget = descriptor.fget - redirect.fset = descriptor.fset - redirect.fdel = descriptor.fdel + # earlier descriptor found; copy fget, fset, fdel to this one. + redirect.fget = found_descriptor.fget + redirect.fset = found_descriptor.fset + redirect.fdel = found_descriptor.fdel setattr(enum_class, member_name, redirect) else: setattr(enum_class, member_name, enum_member) diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 09060733bc51..51dd66bea0c4 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -2621,14 +2621,15 @@ class Private(Enum): self.assertEqual(Private._Private__corporal, 'Radar') self.assertEqual(Private._Private__major_, 'Hoolihan') - @unittest.skip("Accessing all values retained for performance reasons, see GH-93910") - def test_exception_for_member_from_member_access(self): - with self.assertRaisesRegex(AttributeError, " member has no attribute .NO."): - class Di(Enum): - YES = 1 - NO = 0 - nope = Di.YES.NO - + def test_member_from_member_access(self): + class Di(Enum): + YES = 1 + NO = 0 + name = 3 + warn = Di.YES.NO + self.assertIs(warn, Di.NO) + self.assertIs(Di.name, Di['name']) + self.assertEqual(Di.name.name, 'name') def test_dynamic_members_with_static_methods(self): # diff --git a/Misc/NEWS.d/next/Library/2023-04-04-12-43-38.gh-issue-93910.jurMzv.rst b/Misc/NEWS.d/next/Library/2023-04-04-12-43-38.gh-issue-93910.jurMzv.rst new file mode 100644 index 000000000000..783aefae0770 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-04-12-43-38.gh-issue-93910.jurMzv.rst @@ -0,0 +1 @@ +Remove deprecation of enum ``memmber.member`` access. From webhook-mailer at python.org Thu Apr 6 00:30:17 2023 From: webhook-mailer at python.org (ethanfurman) Date: Thu, 06 Apr 2023 04:30:17 -0000 Subject: [Python-checkins] [Enum] unchain exception property.__get__ (GH-103305) Message-ID: https://github.com/python/cpython/commit/a44568b80dfc494759d45db59423ed314bc70f9e commit: a44568b80dfc494759d45db59423ed314bc70f9e branch: main author: Ethan Furman committer: ethanfurman date: 2023-04-05T21:30:11-07:00 summary: [Enum] unchain exception property.__get__ (GH-103305) files: M Lib/enum.py diff --git a/Lib/enum.py b/Lib/enum.py index 0b0629cf9205..10902c4b202a 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -207,7 +207,7 @@ def __get__(self, instance, ownerclass=None): except KeyError: raise AttributeError( '%r has no attribute %r' % (ownerclass, self.name) - ) + ) from None else: return self.fget(instance) From webhook-mailer at python.org Thu Apr 6 06:08:32 2023 From: webhook-mailer at python.org (iritkatriel) Date: Thu, 06 Apr 2023 10:08:32 -0000 Subject: [Python-checkins] gh-102799: use sys.exception() instead of sys.exc_info() in tests (#103293) Message-ID: https://github.com/python/cpython/commit/482b6eeadcde3e6573f0d243e687de7be7680379 commit: 482b6eeadcde3e6573f0d243e687de7be7680379 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-04-06T11:08:25+01:00 summary: gh-102799: use sys.exception() instead of sys.exc_info() in tests (#103293) files: M Lib/test/profilee.py M Lib/test/support/asyncore.py M Lib/test/test_asyncio/test_tasks.py M Lib/test/test_asyncio/utils.py M Lib/test/test_class.py M Lib/test/test_cprofile.py M Lib/test/test_exceptions.py M Lib/test/test_generators.py M Lib/test/test_logging.py M Lib/test/test_profile.py M Lib/test/test_ssl.py M Lib/test/test_traceback.py diff --git a/Lib/test/profilee.py b/Lib/test/profilee.py index 6ad2c8395634..b6a090a2e346 100644 --- a/Lib/test/profilee.py +++ b/Lib/test/profilee.py @@ -79,7 +79,7 @@ def helper1(): TICKS += 19 lst = [] lst.append(42) # 0 - sys.exc_info() # 0 + sys.exception() # 0 def helper2_indirect(): helper2() # 50 diff --git a/Lib/test/support/asyncore.py b/Lib/test/support/asyncore.py index 401fa60bcf35..b397aca55680 100644 --- a/Lib/test/support/asyncore.py +++ b/Lib/test/support/asyncore.py @@ -537,10 +537,11 @@ def send(self, data): # --------------------------------------------------------------------------- def compact_traceback(): - t, v, tb = sys.exc_info() - tbinfo = [] + exc = sys.exception() + tb = exc.__traceback__ if not tb: # Must have a traceback raise AssertionError("traceback does not exist") + tbinfo = [] while tb: tbinfo.append(( tb.tb_frame.f_code.co_filename, @@ -554,7 +555,7 @@ def compact_traceback(): file, function, line = tbinfo[-1] info = ' '.join(['[%s|%s|%s]' % x for x in tbinfo]) - return (file, function, line), t, v, info + return (file, function, line), type(exc), exc, info def close_all(map=None, ignore_all=False): if map is None: diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 731fa0c5a60b..31622c91470b 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -606,7 +606,7 @@ def on_timeout(): if ( timed_out and task.uncancel() == 0 - and sys.exc_info()[0] is asyncio.CancelledError + and type(sys.exception()) is asyncio.CancelledError ): # Note the five rules that are needed here to satisfy proper # uncancellation: diff --git a/Lib/test/test_asyncio/utils.py b/Lib/test/test_asyncio/utils.py index 5b9c86eb9859..6dee5bb33b25 100644 --- a/Lib/test/test_asyncio/utils.py +++ b/Lib/test/test_asyncio/utils.py @@ -577,7 +577,7 @@ def tearDown(self): # Detect CPython bug #23353: ensure that yield/yield-from is not used # in an except block of a generator - self.assertEqual(sys.exc_info(), (None, None, None)) + self.assertIsNone(sys.exception()) self.doCleanups() threading_helper.threading_cleanup(*self._thread_cleanup) diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index 61df81b16977..d7a48e55b101 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -457,7 +457,7 @@ def __init__(self): a = A() self.assertEqual(_testcapi.hasattr_string(a, "attr"), True) self.assertEqual(_testcapi.hasattr_string(a, "noattr"), False) - self.assertEqual(sys.exc_info(), (None, None, None)) + self.assertIsNone(sys.exception()) def testDel(self): x = [] diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py index 4ec769885292..98648528bc81 100644 --- a/Lib/test/test_cprofile.py +++ b/Lib/test/test_cprofile.py @@ -100,7 +100,7 @@ def main(): profilee.py:98(subhelper) <- 8 0.064 0.080 profilee.py:88(helper2) {built-in method builtins.hasattr} <- 4 0.000 0.004 profilee.py:73(helper1) 8 0.000 0.008 profilee.py:88(helper2) -{built-in method sys.exc_info} <- 4 0.000 0.000 profilee.py:73(helper1) +{built-in method sys.exception} <- 4 0.000 0.000 profilee.py:73(helper1) {method 'append' of 'list' objects} <- 4 0.000 0.000 profilee.py:73(helper1)""" _ProfileOutput['print_callees'] = """\ :1() -> 1 0.270 1.000 profilee.py:25(testfunc) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 74a5884264d5..684e888f08c7 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -334,8 +334,7 @@ def test_capi1(): try: _testcapi.raise_exception(BadException, 1) except TypeError as err: - exc, err, tb = sys.exc_info() - co = tb.tb_frame.f_code + co = err.__traceback__.tb_frame.f_code self.assertEqual(co.co_name, "test_capi1") self.assertTrue(co.co_filename.endswith('test_exceptions.py')) else: @@ -346,8 +345,7 @@ def test_capi2(): try: _testcapi.raise_exception(BadException, 0) except RuntimeError as err: - exc, err, tb = sys.exc_info() - tb = tb.tb_next + tb = err.__traceback__.tb_next co = tb.tb_frame.f_code self.assertEqual(co.co_name, "__init__") self.assertTrue(co.co_filename.endswith('test_exceptions.py')) @@ -888,28 +886,28 @@ def yield_raise(): try: raise KeyError("caught") except KeyError: - yield sys.exc_info()[0] - yield sys.exc_info()[0] - yield sys.exc_info()[0] + yield sys.exception() + yield sys.exception() + yield sys.exception() g = yield_raise() - self.assertEqual(next(g), KeyError) - self.assertEqual(sys.exc_info()[0], None) - self.assertEqual(next(g), KeyError) - self.assertEqual(sys.exc_info()[0], None) - self.assertEqual(next(g), None) + self.assertIsInstance(next(g), KeyError) + self.assertIsNone(sys.exception()) + self.assertIsInstance(next(g), KeyError) + self.assertIsNone(sys.exception()) + self.assertIsNone(next(g)) # Same test, but inside an exception handler try: raise TypeError("foo") except TypeError: g = yield_raise() - self.assertEqual(next(g), KeyError) - self.assertEqual(sys.exc_info()[0], TypeError) - self.assertEqual(next(g), KeyError) - self.assertEqual(sys.exc_info()[0], TypeError) - self.assertEqual(next(g), TypeError) + self.assertIsInstance(next(g), KeyError) + self.assertIsInstance(sys.exception(), TypeError) + self.assertIsInstance(next(g), KeyError) + self.assertIsInstance(sys.exception(), TypeError) + self.assertIsInstance(next(g), TypeError) del g - self.assertEqual(sys.exc_info()[0], TypeError) + self.assertIsInstance(sys.exception(), TypeError) def test_generator_leaking2(self): # See issue 12475. @@ -924,7 +922,7 @@ def g(): next(it) except StopIteration: pass - self.assertEqual(sys.exc_info(), (None, None, None)) + self.assertIsNone(sys.exception()) def test_generator_leaking3(self): # See issue #23353. When gen.throw() is called, the caller's @@ -933,17 +931,17 @@ def g(): try: yield except ZeroDivisionError: - yield sys.exc_info()[1] + yield sys.exception() it = g() next(it) try: 1/0 except ZeroDivisionError as e: - self.assertIs(sys.exc_info()[1], e) + self.assertIs(sys.exception(), e) gen_exc = it.throw(e) - self.assertIs(sys.exc_info()[1], e) + self.assertIs(sys.exception(), e) self.assertIs(gen_exc, e) - self.assertEqual(sys.exc_info(), (None, None, None)) + self.assertIsNone(sys.exception()) def test_generator_leaking4(self): # See issue #23353. When an exception is raised by a generator, @@ -952,7 +950,7 @@ def g(): try: 1/0 except ZeroDivisionError: - yield sys.exc_info()[0] + yield sys.exception() raise it = g() try: @@ -960,7 +958,7 @@ def g(): except TypeError: # The caller's exception state (TypeError) is temporarily # saved in the generator. - tp = next(it) + tp = type(next(it)) self.assertIs(tp, ZeroDivisionError) try: next(it) @@ -968,15 +966,15 @@ def g(): # with an exception, it shouldn't have restored the old # exception state (TypeError). except ZeroDivisionError as e: - self.assertIs(sys.exc_info()[1], e) + self.assertIs(sys.exception(), e) # We used to find TypeError here. - self.assertEqual(sys.exc_info(), (None, None, None)) + self.assertIsNone(sys.exception()) def test_generator_doesnt_retain_old_exc(self): def g(): - self.assertIsInstance(sys.exc_info()[1], RuntimeError) + self.assertIsInstance(sys.exception(), RuntimeError) yield - self.assertEqual(sys.exc_info(), (None, None, None)) + self.assertIsNone(sys.exception()) it = g() try: raise RuntimeError @@ -984,7 +982,7 @@ def g(): next(it) self.assertRaises(StopIteration, next, it) - def test_generator_finalizing_and_exc_info(self): + def test_generator_finalizing_and_sys_exception(self): # See #7173 def simple_gen(): yield 1 @@ -996,7 +994,7 @@ def run_gen(): return next(gen) run_gen() gc_collect() - self.assertEqual(sys.exc_info(), (None, None, None)) + self.assertIsNone(sys.exception()) def _check_generator_cleanup_exc_state(self, testfunc): # Issue #12791: exception state is cleaned up as soon as a generator @@ -1067,14 +1065,14 @@ def test_3114(self): class MyObject: def __del__(self): nonlocal e - e = sys.exc_info() + e = sys.exception() e = () try: raise Exception(MyObject()) except: pass gc_collect() # For PyPy or other GCs. - self.assertEqual(e, (None, None, None)) + self.assertIsNone(e) def test_raise_does_not_create_context_chain_cycle(self): class A(Exception): @@ -1692,7 +1690,7 @@ def g(): raise ValueError except ValueError: yield 1 - self.assertEqual(sys.exc_info(), (None, None, None)) + self.assertIsNone(sys.exception()) yield 2 gen = g() diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index 492b77a954d8..a5949dec70d1 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -234,16 +234,16 @@ class ExceptionTest(unittest.TestCase): def test_except_throw(self): def store_raise_exc_generator(): try: - self.assertEqual(sys.exc_info()[0], None) + self.assertIsNone(sys.exception()) yield except Exception as exc: # exception raised by gen.throw(exc) - self.assertEqual(sys.exc_info()[0], ValueError) + self.assertIsInstance(sys.exception(), ValueError) self.assertIsNone(exc.__context__) yield # ensure that the exception is not lost - self.assertEqual(sys.exc_info()[0], ValueError) + self.assertIsInstance(sys.exception(), ValueError) yield # we should be able to raise back the ValueError @@ -265,11 +265,11 @@ def store_raise_exc_generator(): next(make) self.assertIsNone(cm.exception.__context__) - self.assertEqual(sys.exc_info(), (None, None, None)) + self.assertIsNone(sys.exception()) def test_except_next(self): def gen(): - self.assertEqual(sys.exc_info()[0], ValueError) + self.assertIsInstance(sys.exception(), ValueError) yield "done" g = gen() @@ -277,23 +277,23 @@ def gen(): raise ValueError except Exception: self.assertEqual(next(g), "done") - self.assertEqual(sys.exc_info(), (None, None, None)) + self.assertIsNone(sys.exception()) def test_except_gen_except(self): def gen(): try: - self.assertEqual(sys.exc_info()[0], None) + self.assertIsNone(sys.exception()) yield # we are called from "except ValueError:", TypeError must # inherit ValueError in its context raise TypeError() except TypeError as exc: - self.assertEqual(sys.exc_info()[0], TypeError) + self.assertIsInstance(sys.exception(), TypeError) self.assertEqual(type(exc.__context__), ValueError) # here we are still called from the "except ValueError:" - self.assertEqual(sys.exc_info()[0], ValueError) + self.assertIsInstance(sys.exception(), ValueError) yield - self.assertIsNone(sys.exc_info()[0]) + self.assertIsNone(sys.exception()) yield "done" g = gen() @@ -304,7 +304,7 @@ def gen(): next(g) self.assertEqual(next(g), "done") - self.assertEqual(sys.exc_info(), (None, None, None)) + self.assertIsNone(sys.exception()) def test_nested_gen_except_loop(self): def gen(): @@ -330,19 +330,19 @@ def test_except_throw_exception_context(self): def gen(): try: try: - self.assertEqual(sys.exc_info()[0], None) + self.assertIsNone(sys.exception()) yield except ValueError: # we are called from "except ValueError:" - self.assertEqual(sys.exc_info()[0], ValueError) + self.assertIsInstance(sys.exception(), ValueError) raise TypeError() except Exception as exc: - self.assertEqual(sys.exc_info()[0], TypeError) + self.assertIsInstance(sys.exception(), TypeError) self.assertEqual(type(exc.__context__), ValueError) # we are still called from "except ValueError:" - self.assertEqual(sys.exc_info()[0], ValueError) + self.assertIsInstance(sys.exception(), ValueError) yield - self.assertIsNone(sys.exc_info()[0]) + self.assertIsNone(sys.exception()) yield "done" g = gen() @@ -353,7 +353,7 @@ def gen(): g.throw(exc) self.assertEqual(next(g), "done") - self.assertEqual(sys.exc_info(), (None, None, None)) + self.assertIsNone(sys.exception()) def test_except_throw_bad_exception(self): class E(Exception): diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 072056d37221..c6de34e9dbdc 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -5097,8 +5097,7 @@ def test_encoding_errors_none(self): message = [] def dummy_handle_error(record): - _, v, _ = sys.exc_info() - message.append(str(v)) + message.append(str(sys.exception())) handler.handleError = dummy_handle_error logging.debug('The ?resund Bridge joins Copenhagen to Malm?') diff --git a/Lib/test/test_profile.py b/Lib/test/test_profile.py index d97fe447c38b..a1dfc9abbb8e 100644 --- a/Lib/test/test_profile.py +++ b/Lib/test/test_profile.py @@ -178,7 +178,7 @@ def main(): 8 63.976 7.997 79.960 9.995 profilee.py:98(subhelper)""" _ProfileOutput['print_callers'] = """\ :0(append) <- profilee.py:73(helper1)(4) 119.964 -:0(exc_info) <- profilee.py:73(helper1)(4) 119.964 +:0(exception) <- profilee.py:73(helper1)(4) 119.964 :0(hasattr) <- profilee.py:73(helper1)(4) 119.964 profilee.py:88(helper2)(8) 399.912 profilee.py:110(__getattr__) <- :0(hasattr)(12) 11.964 diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index abf024fb89d2..d46ce5e60e21 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -253,7 +253,7 @@ def wrapper(*args, **kw): def handle_error(prefix): - exc_format = ' '.join(traceback.format_exception(*sys.exc_info())) + exc_format = ' '.join(traceback.format_exception(sys.exception())) if support.verbose: sys.stdout.write(prefix + exc_format) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 399c59f8780d..a6172ff05eed 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -1211,8 +1211,7 @@ def test_recursive_traceback_python(self): def test_recursive_traceback_cpython_internal(self): from _testcapi import exception_print def render_exc(): - exc_type, exc_value, exc_tb = sys.exc_info() - exception_print(exc_value) + exception_print(sys.exception()) self._check_recursive_traceback_display(render_exc) def test_format_stack(self): @@ -2470,8 +2469,8 @@ def test_cause(self): try: 1/0 finally: - exc_info_context = sys.exc_info() - exc_context = traceback.TracebackException(*exc_info_context) + exc = sys.exception() + exc_context = traceback.TracebackException.from_exception(exc) cause = Exception("cause") raise Exception("uh oh") from cause except Exception as e: @@ -2492,8 +2491,8 @@ def test_context(self): try: 1/0 finally: - exc_info_context = sys.exc_info() - exc_context = traceback.TracebackException(*exc_info_context) + exc = sys.exception() + exc_context = traceback.TracebackException.from_exception(exc) raise Exception("uh oh") except Exception as e: exc_obj = e @@ -2557,8 +2556,8 @@ def test_compact_no_cause(self): try: 1/0 finally: - exc_info_context = sys.exc_info() - exc_context = traceback.TracebackException(*exc_info_context) + exc = sys.exception() + exc_context = traceback.TracebackException.from_exception(exc) raise Exception("uh oh") except Exception as e: exc_obj = e From webhook-mailer at python.org Thu Apr 6 09:05:30 2023 From: webhook-mailer at python.org (iritkatriel) Date: Thu, 06 Apr 2023 13:05:30 -0000 Subject: [Python-checkins] gh-48330: assert warning is emitted on unittest.TestResult with no addDuration (#103309) Message-ID: https://github.com/python/cpython/commit/52bc2e7b9d451821513a580a9b73c20cfdcf2b21 commit: 52bc2e7b9d451821513a580a9b73c20cfdcf2b21 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-04-06T14:05:23+01:00 summary: gh-48330: assert warning is emitted on unittest.TestResult with no addDuration (#103309) files: M Lib/test/test_unittest/test_case.py diff --git a/Lib/test/test_unittest/test_case.py b/Lib/test/test_unittest/test_case.py index 05d60a8ad3cf..dd5ff6d553e6 100644 --- a/Lib/test/test_unittest/test_case.py +++ b/Lib/test/test_unittest/test_case.py @@ -304,7 +304,8 @@ def defaultTestResult(self): def test(self): pass - Foo('test').run() + with self.assertWarns(RuntimeWarning): + Foo('test').run() def test_deprecation_of_return_val_from_test(self): # Issue 41322 - deprecate return of value that is not None from a test From webhook-mailer at python.org Thu Apr 6 11:59:44 2023 From: webhook-mailer at python.org (vstinner) Date: Thu, 06 Apr 2023 15:59:44 -0000 Subject: [Python-checkins] gh-99202: Fix extension type from documentation for compiling in C++20 mode (#102518) Message-ID: https://github.com/python/cpython/commit/23cf1e20a6470588fbc64483031ceeec7614dc56 commit: 23cf1e20a6470588fbc64483031ceeec7614dc56 branch: main author: Jeffrey Newman committer: vstinner date: 2023-04-06T17:59:36+02:00 summary: gh-99202: Fix extension type from documentation for compiling in C++20 mode (#102518) files: A Misc/NEWS.d/next/Documentation/2023-03-07-23-30-29.gh-issue-99202.hhiAJF.rst M Doc/extending/newtypes_tutorial.rst M Doc/includes/custom.c M Doc/includes/custom2.c M Doc/includes/custom3.c M Doc/includes/custom4.c diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst index 54de3fd42437..f89934a11f12 100644 --- a/Doc/extending/newtypes_tutorial.rst +++ b/Doc/extending/newtypes_tutorial.rst @@ -88,7 +88,7 @@ standard Python floats:: The second bit is the definition of the type object. :: static PyTypeObject CustomType = { - PyVarObject_HEAD_INIT(NULL, 0) + .ob_base = PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "custom.Custom", .tp_doc = PyDoc_STR("Custom objects"), .tp_basicsize = sizeof(CustomObject), @@ -109,7 +109,7 @@ common practice to not specify them explicitly unless you need them. We're going to pick it apart, one field at a time:: - PyVarObject_HEAD_INIT(NULL, 0) + .ob_base = PyVarObject_HEAD_INIT(NULL, 0) This line is mandatory boilerplate to initialize the ``ob_base`` field mentioned above. :: diff --git a/Doc/includes/custom.c b/Doc/includes/custom.c index 26ca75496473..9cfba50ace25 100644 --- a/Doc/includes/custom.c +++ b/Doc/includes/custom.c @@ -7,7 +7,7 @@ typedef struct { } CustomObject; static PyTypeObject CustomType = { - PyVarObject_HEAD_INIT(NULL, 0) + .ob_base = PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "custom.Custom", .tp_doc = PyDoc_STR("Custom objects"), .tp_basicsize = sizeof(CustomObject), @@ -17,7 +17,7 @@ static PyTypeObject CustomType = { }; static PyModuleDef custommodule = { - PyModuleDef_HEAD_INIT, + .m_base = PyModuleDef_HEAD_INIT, .m_name = "custom", .m_doc = "Example module that creates an extension type.", .m_size = -1, diff --git a/Doc/includes/custom2.c b/Doc/includes/custom2.c index a3b2d6ab78d3..a0222b179520 100644 --- a/Doc/includes/custom2.c +++ b/Doc/includes/custom2.c @@ -90,7 +90,7 @@ static PyMethodDef Custom_methods[] = { }; static PyTypeObject CustomType = { - PyVarObject_HEAD_INIT(NULL, 0) + .ob_base = PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "custom2.Custom", .tp_doc = PyDoc_STR("Custom objects"), .tp_basicsize = sizeof(CustomObject), @@ -104,7 +104,7 @@ static PyTypeObject CustomType = { }; static PyModuleDef custommodule = { - PyModuleDef_HEAD_INIT, + .m_base =PyModuleDef_HEAD_INIT, .m_name = "custom2", .m_doc = "Example module that creates an extension type.", .m_size = -1, diff --git a/Doc/includes/custom3.c b/Doc/includes/custom3.c index 1a68bc4be8c3..4aeebe0a7507 100644 --- a/Doc/includes/custom3.c +++ b/Doc/includes/custom3.c @@ -130,7 +130,7 @@ static PyMethodDef Custom_methods[] = { }; static PyTypeObject CustomType = { - PyVarObject_HEAD_INIT(NULL, 0) + .ob_base = PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "custom3.Custom", .tp_doc = PyDoc_STR("Custom objects"), .tp_basicsize = sizeof(CustomObject), @@ -145,7 +145,7 @@ static PyTypeObject CustomType = { }; static PyModuleDef custommodule = { - PyModuleDef_HEAD_INIT, + .m_base = PyModuleDef_HEAD_INIT, .m_name = "custom3", .m_doc = "Example module that creates an extension type.", .m_size = -1, diff --git a/Doc/includes/custom4.c b/Doc/includes/custom4.c index b932d159d26e..3998918f6830 100644 --- a/Doc/includes/custom4.c +++ b/Doc/includes/custom4.c @@ -146,7 +146,7 @@ static PyMethodDef Custom_methods[] = { }; static PyTypeObject CustomType = { - PyVarObject_HEAD_INIT(NULL, 0) + .ob_base = PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "custom4.Custom", .tp_doc = PyDoc_STR("Custom objects"), .tp_basicsize = sizeof(CustomObject), @@ -163,7 +163,7 @@ static PyTypeObject CustomType = { }; static PyModuleDef custommodule = { - PyModuleDef_HEAD_INIT, + .m_base = PyModuleDef_HEAD_INIT, .m_name = "custom4", .m_doc = "Example module that creates an extension type.", .m_size = -1, diff --git a/Misc/NEWS.d/next/Documentation/2023-03-07-23-30-29.gh-issue-99202.hhiAJF.rst b/Misc/NEWS.d/next/Documentation/2023-03-07-23-30-29.gh-issue-99202.hhiAJF.rst new file mode 100644 index 000000000000..1569e815ee50 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-03-07-23-30-29.gh-issue-99202.hhiAJF.rst @@ -0,0 +1 @@ +Fix extension type from documentation for compiling in C++20 mode From webhook-mailer at python.org Thu Apr 6 14:00:57 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Thu, 06 Apr 2023 18:00:57 -0000 Subject: [Python-checkins] gh-100227: Use an Array for _PyRuntime's Set of Locks During Init (gh-103315) Message-ID: https://github.com/python/cpython/commit/52e9b389a8773f485c3b0f1d62bf3cce4812d44d commit: 52e9b389a8773f485c3b0f1d62bf3cce4812d44d branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-04-06T12:00:49-06:00 summary: gh-100227: Use an Array for _PyRuntime's Set of Locks During Init (gh-103315) This cleans things up a bit and simplifies adding new granular global locks. files: M Python/pystate.c diff --git a/Python/pystate.c b/Python/pystate.c index 1e59a8c5f897..d09c1d5743a4 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -354,47 +354,29 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime); _Py_COMP_DIAG_POP +#define NUMLOCKS 4 + static int -alloc_for_runtime(PyThread_type_lock *plock1, PyThread_type_lock *plock2, - PyThread_type_lock *plock3, PyThread_type_lock *plock4) +alloc_for_runtime(PyThread_type_lock locks[NUMLOCKS]) { /* Force default allocator, since _PyRuntimeState_Fini() must use the same allocator than this function. */ PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - PyThread_type_lock lock1 = PyThread_allocate_lock(); - if (lock1 == NULL) { - return -1; - } - - PyThread_type_lock lock2 = PyThread_allocate_lock(); - if (lock2 == NULL) { - PyThread_free_lock(lock1); - return -1; - } - - PyThread_type_lock lock3 = PyThread_allocate_lock(); - if (lock3 == NULL) { - PyThread_free_lock(lock1); - PyThread_free_lock(lock2); - return -1; - } - - PyThread_type_lock lock4 = PyThread_allocate_lock(); - if (lock4 == NULL) { - PyThread_free_lock(lock1); - PyThread_free_lock(lock2); - PyThread_free_lock(lock3); - return -1; + for (int i = 0; i < NUMLOCKS; i++) { + PyThread_type_lock lock = PyThread_allocate_lock(); + if (lock == NULL) { + for (int j = 0; j < i; j++) { + PyThread_free_lock(locks[j]); + locks[j] = NULL; + } + break; + } + locks[i] = lock; } PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - - *plock1 = lock1; - *plock2 = lock2; - *plock3 = lock3; - *plock4 = lock4; return 0; } @@ -403,10 +385,7 @@ init_runtime(_PyRuntimeState *runtime, void *open_code_hook, void *open_code_userdata, _Py_AuditHookEntry *audit_hook_head, Py_ssize_t unicode_next_index, - PyThread_type_lock unicode_ids_mutex, - PyThread_type_lock interpreters_mutex, - PyThread_type_lock xidregistry_mutex, - PyThread_type_lock getargs_mutex) + PyThread_type_lock locks[NUMLOCKS]) { if (runtime->_initialized) { Py_FatalError("runtime already initialized"); @@ -424,17 +403,21 @@ init_runtime(_PyRuntimeState *runtime, PyPreConfig_InitPythonConfig(&runtime->preconfig); - runtime->interpreters.mutex = interpreters_mutex; - - runtime->xidregistry.mutex = xidregistry_mutex; - - runtime->getargs.mutex = getargs_mutex; + PyThread_type_lock *lockptrs[NUMLOCKS] = { + &runtime->interpreters.mutex, + &runtime->xidregistry.mutex, + &runtime->getargs.mutex, + &runtime->unicode_state.ids.lock, + }; + for (int i = 0; i < NUMLOCKS; i++) { + assert(locks[i] != NULL); + *lockptrs[i] = locks[i]; + } // Set it to the ID of the main thread of the main interpreter. runtime->main_thread = PyThread_get_thread_ident(); runtime->unicode_state.ids.next_index = unicode_next_index; - runtime->unicode_state.ids.lock = unicode_ids_mutex; runtime->_initialized = 1; } @@ -452,8 +435,8 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime) // is called multiple times. Py_ssize_t unicode_next_index = runtime->unicode_state.ids.next_index; - PyThread_type_lock lock1, lock2, lock3, lock4; - if (alloc_for_runtime(&lock1, &lock2, &lock3, &lock4) != 0) { + PyThread_type_lock locks[NUMLOCKS]; + if (alloc_for_runtime(locks) != 0) { return _PyStatus_NO_MEMORY(); } @@ -474,7 +457,7 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime) } init_runtime(runtime, open_code_hook, open_code_userdata, audit_hook_head, - unicode_next_index, lock1, lock2, lock3, lock4); + unicode_next_index, locks); return _PyStatus_OK(); } @@ -504,10 +487,15 @@ _PyRuntimeState_Fini(_PyRuntimeState *runtime) LOCK = NULL; \ } - FREE_LOCK(runtime->interpreters.mutex); - FREE_LOCK(runtime->xidregistry.mutex); - FREE_LOCK(runtime->unicode_state.ids.lock); - FREE_LOCK(runtime->getargs.mutex); + PyThread_type_lock *lockptrs[NUMLOCKS] = { + &runtime->interpreters.mutex, + &runtime->xidregistry.mutex, + &runtime->getargs.mutex, + &runtime->unicode_state.ids.lock, + }; + for (int i = 0; i < NUMLOCKS; i++) { + FREE_LOCK(*lockptrs[i]); + } #undef FREE_LOCK PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); @@ -527,25 +515,25 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime) PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); - int reinit_interp = _PyThread_at_fork_reinit(&runtime->interpreters.mutex); - int reinit_xidregistry = _PyThread_at_fork_reinit(&runtime->xidregistry.mutex); - int reinit_unicode_ids = _PyThread_at_fork_reinit(&runtime->unicode_state.ids.lock); - int reinit_getargs = _PyThread_at_fork_reinit(&runtime->getargs.mutex); + PyThread_type_lock *lockptrs[NUMLOCKS] = { + &runtime->interpreters.mutex, + &runtime->xidregistry.mutex, + &runtime->getargs.mutex, + &runtime->unicode_state.ids.lock, + }; + int reinit_err = 0; + for (int i = 0; i < NUMLOCKS; i++) { + reinit_err += _PyThread_at_fork_reinit(lockptrs[i]); + } PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); /* bpo-42540: id_mutex is freed by _PyInterpreterState_Delete, which does * not force the default allocator. */ - int reinit_main_id = _PyThread_at_fork_reinit(&runtime->interpreters.main->id_mutex); + reinit_err += _PyThread_at_fork_reinit(&runtime->interpreters.main->id_mutex); - if (reinit_interp < 0 - || reinit_main_id < 0 - || reinit_xidregistry < 0 - || reinit_unicode_ids < 0 - || reinit_getargs < 0) - { + if (reinit_err < 0) { return _PyStatus_ERR("Failed to reinitialize runtime locks"); - } PyStatus status = gilstate_tss_reinit(runtime); From webhook-mailer at python.org Thu Apr 6 14:13:53 2023 From: webhook-mailer at python.org (iritkatriel) Date: Thu, 06 Apr 2023 18:13:53 -0000 Subject: [Python-checkins] gh-103186: assert in tests that UnsafeMailcapInput warnings are provided (#103217) Message-ID: https://github.com/python/cpython/commit/1724553e6e8baae655901488968a40df981f32da commit: 1724553e6e8baae655901488968a40df981f32da branch: main author: Ijtaba Hussain committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-04-06T19:13:33+01:00 summary: gh-103186: assert in tests that UnsafeMailcapInput warnings are provided (#103217) files: M Lib/test/test_mailcap.py diff --git a/Lib/test/test_mailcap.py b/Lib/test/test_mailcap.py index 819dc80a2664..8a94b0cb1f27 100644 --- a/Lib/test/test_mailcap.py +++ b/Lib/test/test_mailcap.py @@ -127,7 +127,6 @@ def test_subst(self): (["", "audio/*", "foo.txt"], ""), (["echo foo", "audio/*", "foo.txt"], "echo foo"), (["echo %s", "audio/*", "foo.txt"], "echo foo.txt"), - (["echo %t", "audio/*", "foo.txt"], None), (["echo %t", "audio/wav", "foo.txt"], "echo audio/wav"), (["echo \\%t", "audio/*", "foo.txt"], "echo %t"), (["echo foo", "audio/*", "foo.txt", plist], "echo foo"), @@ -210,9 +209,6 @@ def test_findmatch(self): ([c, "audio/basic"], {"key": "description", "filename": fname}, ('"An audio fragment"', audio_basic_entry)), - ([c, "audio/*"], - {"filename": fname}, - (None, None)), ([c, "audio/wav"], {"filename": fname}, ("/usr/local/bin/showaudio audio/wav", audio_entry)), @@ -245,6 +241,30 @@ def test_test(self): ] self._run_cases(cases) + def test_unsafe_mailcap_input(self): + with self.assertWarnsRegex(mailcap.UnsafeMailcapInput, + 'Refusing to substitute parameter.*' + 'into a shell command'): + unsafe_param = mailcap.subst("echo %{total}", + "audio/wav", + "foo.txt", + ["total=*"]) + self.assertEqual(unsafe_param, None) + + with self.assertWarnsRegex(mailcap.UnsafeMailcapInput, + 'Refusing to substitute MIME type' + '.*into a shell'): + unsafe_mimetype = mailcap.subst("echo %t", "audio/*", "foo.txt") + self.assertEqual(unsafe_mimetype, None) + + with self.assertWarnsRegex(mailcap.UnsafeMailcapInput, + 'Refusing to use mailcap with filename.*' + 'Use a safe temporary filename.'): + unsafe_filename = mailcap.findmatch(MAILCAPDICT, + "audio/wav", + filename="foo*.txt") + self.assertEqual(unsafe_filename, (None, None)) + def _run_cases(self, cases): for c in cases: self.assertEqual(mailcap.findmatch(*c[0], **c[1]), c[2]) From webhook-mailer at python.org Thu Apr 6 15:18:06 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Thu, 06 Apr 2023 19:18:06 -0000 Subject: [Python-checkins] gh-103193: Use LBYL idioms rather than EAFP in `inspect.getattr_static` (#103318) Message-ID: https://github.com/python/cpython/commit/affedee8bf2ec00c404ffa39342a593a66bf95bd commit: affedee8bf2ec00c404ffa39342a593a66bf95bd branch: main author: Alex Waygood committer: AlexWaygood date: 2023-04-06T20:17:53+01:00 summary: gh-103193: Use LBYL idioms rather than EAFP in `inspect.getattr_static` (#103318) files: M Lib/inspect.py diff --git a/Lib/inspect.py b/Lib/inspect.py index 8739c9c25726..a317f0ca7488 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1787,11 +1787,8 @@ def _check_instance(obj, attr): def _check_class(klass, attr): for entry in _static_getmro(klass): - if _shadowed_dict(type(entry)) is _sentinel: - try: - return entry.__dict__[attr] - except KeyError: - pass + if _shadowed_dict(type(entry)) is _sentinel and attr in entry.__dict__: + return entry.__dict__[attr] return _sentinel def _is_type(obj): @@ -1803,11 +1800,9 @@ def _is_type(obj): def _shadowed_dict(klass): for entry in _static_getmro(klass): - try: - class_dict = _get_dunder_dict_of_class(entry)["__dict__"] - except KeyError: - pass - else: + dunder_dict = _get_dunder_dict_of_class(entry) + if '__dict__' in dunder_dict: + class_dict = dunder_dict['__dict__'] if not (type(class_dict) is types.GetSetDescriptorType and class_dict.__name__ == "__dict__" and class_dict.__objclass__ is entry): @@ -1850,11 +1845,11 @@ def getattr_static(obj, attr, default=_sentinel): if obj is klass: # for types we check the metaclass too for entry in _static_getmro(type(klass)): - if _shadowed_dict(type(entry)) is _sentinel: - try: - return entry.__dict__[attr] - except KeyError: - pass + if ( + _shadowed_dict(type(entry)) is _sentinel + and attr in entry.__dict__ + ): + return entry.__dict__[attr] if default is not _sentinel: return default raise AttributeError(attr) From webhook-mailer at python.org Thu Apr 6 16:49:31 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Thu, 06 Apr 2023 20:49:31 -0000 Subject: [Python-checkins] gh-103193: Speedup and inline `inspect._is_type` (#103321) Message-ID: https://github.com/python/cpython/commit/dca7d174f1dc3f9e67c7451a27bc92dc5a733008 commit: dca7d174f1dc3f9e67c7451a27bc92dc5a733008 branch: main author: Alex Waygood committer: AlexWaygood date: 2023-04-06T21:49:24+01:00 summary: gh-103193: Speedup and inline `inspect._is_type` (#103321) Improve performance of `inspect.getattr_static` files: M Lib/inspect.py diff --git a/Lib/inspect.py b/Lib/inspect.py index a317f0ca7488..4242b40c2a08 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1791,13 +1791,6 @@ def _check_class(klass, attr): return entry.__dict__[attr] return _sentinel -def _is_type(obj): - try: - _static_getmro(obj) - except TypeError: - return False - return True - def _shadowed_dict(klass): for entry in _static_getmro(klass): dunder_dict = _get_dunder_dict_of_class(entry) @@ -1821,8 +1814,10 @@ def getattr_static(obj, attr, default=_sentinel): documentation for details. """ instance_result = _sentinel - if not _is_type(obj): - klass = type(obj) + + objtype = type(obj) + if type not in _static_getmro(objtype): + klass = objtype dict_attr = _shadowed_dict(klass) if (dict_attr is _sentinel or type(dict_attr) is types.MemberDescriptorType): From webhook-mailer at python.org Thu Apr 6 17:20:02 2023 From: webhook-mailer at python.org (brettcannon) Date: Thu, 06 Apr 2023 21:20:02 -0000 Subject: [Python-checkins] GH-102700: allow built-in modules to be submodules (GH-103162) Message-ID: https://github.com/python/cpython/commit/5d08c3ff7d89ca11556f18663a372f6c12435504 commit: 5d08c3ff7d89ca11556f18663a372f6c12435504 branch: main author: Brett Cannon committer: brettcannon date: 2023-04-06T14:19:54-07:00 summary: GH-102700: allow built-in modules to be submodules (GH-103162) files: A Misc/NEWS.d/next/Core and Builtins/2023-04-01-00-46-31.gh-issue-102700.493NB4.rst M Lib/importlib/_bootstrap.py M Lib/test/test_importlib/builtin/test_finder.py diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index bebe7e15cbce..22fa2469964a 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -887,8 +887,6 @@ class BuiltinImporter: @classmethod def find_spec(cls, fullname, path=None, target=None): - if path is not None: - return None if _imp.is_builtin(fullname): return spec_from_loader(fullname, cls, origin=cls._ORIGIN) else: diff --git a/Lib/test/test_importlib/builtin/test_finder.py b/Lib/test/test_importlib/builtin/test_finder.py index a4869e07b9c0..81dc5a3699d9 100644 --- a/Lib/test/test_importlib/builtin/test_finder.py +++ b/Lib/test/test_importlib/builtin/test_finder.py @@ -37,13 +37,6 @@ def test_failure(self): spec = self.machinery.BuiltinImporter.find_spec(name) self.assertIsNone(spec) - def test_ignore_path(self): - # The value for 'path' should always trigger a failed import. - with util.uncache(util.BUILTINS.good_name): - spec = self.machinery.BuiltinImporter.find_spec(util.BUILTINS.good_name, - ['pkg']) - self.assertIsNone(spec) - (Frozen_FindSpecTests, Source_FindSpecTests @@ -77,16 +70,6 @@ def test_failure(self): loader = self.machinery.BuiltinImporter.find_module('importlib') self.assertIsNone(loader) - def test_ignore_path(self): - # The value for 'path' should always trigger a failed import. - with util.uncache(util.BUILTINS.good_name): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - loader = self.machinery.BuiltinImporter.find_module( - util.BUILTINS.good_name, - ['pkg']) - self.assertIsNone(loader) - (Frozen_FinderTests, Source_FinderTests diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-01-00-46-31.gh-issue-102700.493NB4.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-01-00-46-31.gh-issue-102700.493NB4.rst new file mode 100644 index 000000000000..46951486e4f9 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-01-00-46-31.gh-issue-102700.493NB4.rst @@ -0,0 +1 @@ +Allow built-in modules to be submodules. This allows submodules to be statically linked into a CPython binary. From webhook-mailer at python.org Thu Apr 6 18:19:19 2023 From: webhook-mailer at python.org (iritkatriel) Date: Thu, 06 Apr 2023 22:19:19 -0000 Subject: [Python-checkins] gh-93121: fix test_mailbox where some test cases were accidentally dropped (#93242) Message-ID: https://github.com/python/cpython/commit/a653c32d08abfa34d70186542479e3a7e704f8bd commit: a653c32d08abfa34d70186542479e3a7e704f8bd branch: main author: AGZain <31054801+AGZain at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-04-06T23:19:11+01:00 summary: gh-93121: fix test_mailbox where some test cases were accidentally dropped (#93242) files: M Lib/test/test_mailbox.py diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py index 07c2764dfd1b..4c592eaf34da 100644 --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -31,7 +31,7 @@ def _check_sample(self, msg): # Inspect a mailbox.Message representation of the sample message self.assertIsInstance(msg, email.message.Message) self.assertIsInstance(msg, mailbox.Message) - for key, value in _sample_headers.items(): + for key, value in _sample_headers: self.assertIn(value, msg.get_all(key)) self.assertTrue(msg.is_multipart()) self.assertEqual(len(msg.get_payload()), len(_sample_payloads)) @@ -2264,30 +2264,31 @@ def test_nonempty_maildir_both(self): _bytes_sample_message = _sample_message.encode('ascii') -_sample_headers = { - "Return-Path":"", - "X-Original-To":"gkj+person at localhost", - "Delivered-To":"gkj+person at localhost", - "Received":"""from localhost (localhost [127.0.0.1]) +_sample_headers = [ + ("Return-Path", ""), + ("X-Original-To", "gkj+person at localhost"), + ("Delivered-To", "gkj+person at localhost"), + ("Received", """from localhost (localhost [127.0.0.1]) by andy.gregorykjohnson.com (Postfix) with ESMTP id 356ED9DD17 - for ; Wed, 13 Jul 2005 17:23:16 -0400 (EDT)""", - "Delivered-To":"gkj at sundance.gregorykjohnson.com", - "Received":"""from localhost [127.0.0.1] + for ; Wed, 13 Jul 2005 17:23:16 -0400 (EDT)"""), + ("Delivered-To", "gkj at sundance.gregorykjohnson.com"), + ("Received", """from localhost [127.0.0.1] by localhost with POP3 (fetchmail-6.2.5) - for gkj+person at localhost (single-drop); Wed, 13 Jul 2005 17:23:16 -0400 (EDT)""", - "Received":"""from andy.gregorykjohnson.com (andy.gregorykjohnson.com [64.32.235.228]) + for gkj+person at localhost (single-drop); Wed, 13 Jul 2005 17:23:16 -0400 (EDT)"""), + ("Received", """from andy.gregorykjohnson.com (andy.gregorykjohnson.com [64.32.235.228]) by sundance.gregorykjohnson.com (Postfix) with ESMTP id 5B056316746 - for ; Wed, 13 Jul 2005 17:23:11 -0400 (EDT)""", - "Received":"""by andy.gregorykjohnson.com (Postfix, from userid 1000) - id 490CD9DD17; Wed, 13 Jul 2005 17:23:11 -0400 (EDT)""", - "Date":"Wed, 13 Jul 2005 17:23:11 -0400", - "From":""""Gregory K. Johnson" """, - "To":"gkj at gregorykjohnson.com", - "Subject":"Sample message", - "Mime-Version":"1.0", - "Content-Type":"""multipart/mixed; boundary="NMuMz9nt05w80d4+\"""", - "Content-Disposition":"inline", - "User-Agent": "Mutt/1.5.9i" } + for ; Wed, 13 Jul 2005 17:23:11 -0400 (EDT)"""), + ("Received", """by andy.gregorykjohnson.com (Postfix, from userid 1000) + id 490CD9DD17; Wed, 13 Jul 2005 17:23:11 -0400 (EDT)"""), + ("Date", "Wed, 13 Jul 2005 17:23:11 -0400"), + ("From", """"Gregory K. Johnson" """), + ("To", "gkj at gregorykjohnson.com"), + ("Subject", "Sample message"), + ("Mime-Version", "1.0"), + ("Content-Type", """multipart/mixed; boundary="NMuMz9nt05w80d4+\""""), + ("Content-Disposition", "inline"), + ("User-Agent", "Mutt/1.5.9i"), +] _sample_payloads = ("""This is a sample message. From webhook-mailer at python.org Thu Apr 6 19:06:10 2023 From: webhook-mailer at python.org (brettcannon) Date: Thu, 06 Apr 2023 23:06:10 -0000 Subject: [Python-checkins] [3.11] GH-102700: allow built-in modules to be submodules (GH-103162) (GH-103322) Message-ID: https://github.com/python/cpython/commit/123680f9aa44d3374ba86b63b4ea0c394e13dfe5 commit: 123680f9aa44d3374ba86b63b4ea0c394e13dfe5 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: brettcannon date: 2023-04-06T16:06:02-07:00 summary: [3.11] GH-102700: allow built-in modules to be submodules (GH-103162) (GH-103322) GH-102700: allow built-in modules to be submodules (GH-103162) (cherry picked from commit 5d08c3ff7d89ca11556f18663a372f6c12435504) Co-authored-by: Brett Cannon files: A Misc/NEWS.d/next/Core and Builtins/2023-04-01-00-46-31.gh-issue-102700.493NB4.rst M Lib/importlib/_bootstrap.py M Lib/test/test_importlib/builtin/test_finder.py diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index afb95f4e1df8..ee93ebc3960c 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -747,8 +747,6 @@ def module_repr(module): @classmethod def find_spec(cls, fullname, path=None, target=None): - if path is not None: - return None if _imp.is_builtin(fullname): return spec_from_loader(fullname, cls, origin=cls._ORIGIN) else: diff --git a/Lib/test/test_importlib/builtin/test_finder.py b/Lib/test/test_importlib/builtin/test_finder.py index a4869e07b9c0..81dc5a3699d9 100644 --- a/Lib/test/test_importlib/builtin/test_finder.py +++ b/Lib/test/test_importlib/builtin/test_finder.py @@ -37,13 +37,6 @@ def test_failure(self): spec = self.machinery.BuiltinImporter.find_spec(name) self.assertIsNone(spec) - def test_ignore_path(self): - # The value for 'path' should always trigger a failed import. - with util.uncache(util.BUILTINS.good_name): - spec = self.machinery.BuiltinImporter.find_spec(util.BUILTINS.good_name, - ['pkg']) - self.assertIsNone(spec) - (Frozen_FindSpecTests, Source_FindSpecTests @@ -77,16 +70,6 @@ def test_failure(self): loader = self.machinery.BuiltinImporter.find_module('importlib') self.assertIsNone(loader) - def test_ignore_path(self): - # The value for 'path' should always trigger a failed import. - with util.uncache(util.BUILTINS.good_name): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - loader = self.machinery.BuiltinImporter.find_module( - util.BUILTINS.good_name, - ['pkg']) - self.assertIsNone(loader) - (Frozen_FinderTests, Source_FinderTests diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-01-00-46-31.gh-issue-102700.493NB4.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-01-00-46-31.gh-issue-102700.493NB4.rst new file mode 100644 index 000000000000..46951486e4f9 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-01-00-46-31.gh-issue-102700.493NB4.rst @@ -0,0 +1 @@ +Allow built-in modules to be submodules. This allows submodules to be statically linked into a CPython binary. From webhook-mailer at python.org Thu Apr 6 20:34:26 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Fri, 07 Apr 2023 00:34:26 -0000 Subject: [Python-checkins] gh-103266: Fix a typo in example code for bisect() function (#103267) Message-ID: https://github.com/python/cpython/commit/f0424ba4b6663d2a4240239266bea08aff46bb6c commit: f0424ba4b6663d2a4240239266bea08aff46bb6c branch: main author: Oleg Iarygin committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-04-06T17:34:19-07:00 summary: gh-103266: Fix a typo in example code for bisect() function (#103267) files: M Doc/library/bisect.rst diff --git a/Doc/library/bisect.rst b/Doc/library/bisect.rst index b85564f17866..e3c8c801904b 100644 --- a/Doc/library/bisect.rst +++ b/Doc/library/bisect.rst @@ -210,10 +210,10 @@ records in a table:: >>> Movie = namedtuple('Movie', ('name', 'released', 'director')) >>> movies = [ - ... Movie('Jaws', 1975, 'Speilberg'), + ... Movie('Jaws', 1975, 'Spielberg'), ... Movie('Titanic', 1997, 'Cameron'), ... Movie('The Birds', 1963, 'Hitchcock'), - ... Movie('Aliens', 1986, 'Scott') + ... Movie('Aliens', 1986, 'Cameron') ... ] >>> # Find the first movie released after 1960 @@ -228,8 +228,8 @@ records in a table:: >>> pprint(movies) [Movie(name='The Birds', released=1963, director='Hitchcock'), Movie(name='Love Story', released=1970, director='Hiller'), - Movie(name='Jaws', released=1975, director='Speilberg'), - Movie(name='Aliens', released=1986, director='Scott'), + Movie(name='Jaws', released=1975, director='Spielberg'), + Movie(name='Aliens', released=1986, director='Cameron'), Movie(name='Titanic', released=1997, director='Cameron')] If the key function is expensive, it is possible to avoid repeated function From webhook-mailer at python.org Thu Apr 6 20:45:20 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Apr 2023 00:45:20 -0000 Subject: [Python-checkins] gh-103266: Fix a typo in example code for bisect() function (GH-103267) Message-ID: https://github.com/python/cpython/commit/bbe04d9d1cfc68c30d18798cbb6ffa7346555b4b commit: bbe04d9d1cfc68c30d18798cbb6ffa7346555b4b branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-06T17:45:07-07:00 summary: gh-103266: Fix a typo in example code for bisect() function (GH-103267) (cherry picked from commit f0424ba4b6663d2a4240239266bea08aff46bb6c) Co-authored-by: Oleg Iarygin files: M Doc/library/bisect.rst diff --git a/Doc/library/bisect.rst b/Doc/library/bisect.rst index 9b40f80f5878..19aeae0dc60e 100644 --- a/Doc/library/bisect.rst +++ b/Doc/library/bisect.rst @@ -210,10 +210,10 @@ records in a table:: >>> Movie = namedtuple('Movie', ('name', 'released', 'director')) >>> movies = [ - ... Movie('Jaws', 1975, 'Speilberg'), + ... Movie('Jaws', 1975, 'Spielberg'), ... Movie('Titanic', 1997, 'Cameron'), ... Movie('The Birds', 1963, 'Hitchcock'), - ... Movie('Aliens', 1986, 'Scott') + ... Movie('Aliens', 1986, 'Cameron') ... ] >>> # Find the first movie released after 1960 @@ -228,8 +228,8 @@ records in a table:: >>> pprint(movies) [Movie(name='The Birds', released=1963, director='Hitchcock'), Movie(name='Love Story', released=1970, director='Hiller'), - Movie(name='Jaws', released=1975, director='Speilberg'), - Movie(name='Aliens', released=1986, director='Scott'), + Movie(name='Jaws', released=1975, director='Spielberg'), + Movie(name='Aliens', released=1986, director='Cameron'), Movie(name='Titanic', released=1997, director='Cameron')] If the key function is expensive, it is possible to avoid repeated function From webhook-mailer at python.org Thu Apr 6 21:51:46 2023 From: webhook-mailer at python.org (corona10) Date: Fri, 07 Apr 2023 01:51:46 -0000 Subject: [Python-checkins] gh-103256: Fix hmac algorithm to support fallback implementation (gh-103286) Message-ID: https://github.com/python/cpython/commit/efb0a2cf3adf4629cf4669cb558758fb78107319 commit: efb0a2cf3adf4629cf4669cb558758fb78107319 branch: main author: Dong-hee Na committer: corona10 date: 2023-04-07T10:51:29+09:00 summary: gh-103256: Fix hmac algorithm to support fallback implementation (gh-103286) Co-authored-by: Gregory P. Smith files: A Misc/NEWS.d/next/Library/2023-04-06-17-28-36.gh-issue-103256.1syxfs.rst M Lib/test/test_hmac.py M Modules/_hashopenssl.c diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py index 7cf99735ca39..a39a2c45ebc2 100644 --- a/Lib/test/test_hmac.py +++ b/Lib/test/test_hmac.py @@ -373,6 +373,16 @@ def test_with_digestmod_no_default(self): with self.assertRaisesRegex(TypeError, r'required.*digestmod'): hmac.HMAC(key, msg=data, digestmod='') + def test_with_fallback(self): + cache = getattr(hashlib, '__builtin_constructor_cache') + try: + cache['foo'] = hashlib.sha256 + hexdigest = hmac.digest(b'key', b'message', 'foo').hex() + expected = '6e9ef29b75fffc5b7abae527d58fdadb2fe42e7219011976917343065f58ed4a' + self.assertEqual(hexdigest, expected) + finally: + cache.pop('foo') + class ConstructorTestCase(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-04-06-17-28-36.gh-issue-103256.1syxfs.rst b/Misc/NEWS.d/next/Library/2023-04-06-17-28-36.gh-issue-103256.1syxfs.rst new file mode 100644 index 000000000000..894c046dcdf0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-06-17-28-36.gh-issue-103256.1syxfs.rst @@ -0,0 +1,6 @@ +Fixed a bug that caused :mod:`hmac` to raise an exception when the requested +hash algorithm was not available in OpenSSL despite being available +separately as part of ``hashlib`` itself. It now falls back properly to the +built-in. This could happen when, for example, your OpenSSL does not include +SHA3 support and you want to compute ``hmac.digest(b'K', b'M', +'sha3_256')``. diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index ee8c58802011..7476e5dc7dd6 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -355,7 +355,7 @@ py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht) } } if (digest == NULL) { - _setException(PyExc_ValueError, "unsupported hash type %s", name); + _setException(state->unsupported_digestmod_error, "unsupported hash type %s", name); return NULL; } return digest; From webhook-mailer at python.org Thu Apr 6 22:27:54 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Apr 2023 02:27:54 -0000 Subject: [Python-checkins] gh-103256: Fix hmac algorithm to support fallback implementation (gh-103286) Message-ID: https://github.com/python/cpython/commit/8740fd855cea73146c45598d465ce327c14478cb commit: 8740fd855cea73146c45598d465ce327c14478cb branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-06T19:27:46-07:00 summary: gh-103256: Fix hmac algorithm to support fallback implementation (gh-103286) (cherry picked from commit efb0a2cf3adf4629cf4669cb558758fb78107319) Co-authored-by: Dong-hee Na Co-authored-by: Gregory P. Smith files: A Misc/NEWS.d/next/Library/2023-04-06-17-28-36.gh-issue-103256.1syxfs.rst M Lib/test/test_hmac.py M Modules/_hashopenssl.c diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py index 7cf99735ca39..a39a2c45ebc2 100644 --- a/Lib/test/test_hmac.py +++ b/Lib/test/test_hmac.py @@ -373,6 +373,16 @@ def test_with_digestmod_no_default(self): with self.assertRaisesRegex(TypeError, r'required.*digestmod'): hmac.HMAC(key, msg=data, digestmod='') + def test_with_fallback(self): + cache = getattr(hashlib, '__builtin_constructor_cache') + try: + cache['foo'] = hashlib.sha256 + hexdigest = hmac.digest(b'key', b'message', 'foo').hex() + expected = '6e9ef29b75fffc5b7abae527d58fdadb2fe42e7219011976917343065f58ed4a' + self.assertEqual(hexdigest, expected) + finally: + cache.pop('foo') + class ConstructorTestCase(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-04-06-17-28-36.gh-issue-103256.1syxfs.rst b/Misc/NEWS.d/next/Library/2023-04-06-17-28-36.gh-issue-103256.1syxfs.rst new file mode 100644 index 000000000000..894c046dcdf0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-06-17-28-36.gh-issue-103256.1syxfs.rst @@ -0,0 +1,6 @@ +Fixed a bug that caused :mod:`hmac` to raise an exception when the requested +hash algorithm was not available in OpenSSL despite being available +separately as part of ``hashlib`` itself. It now falls back properly to the +built-in. This could happen when, for example, your OpenSSL does not include +SHA3 support and you want to compute ``hmac.digest(b'K', b'M', +'sha3_256')``. diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 3c40f09f7a09..4123c0c6907b 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -360,7 +360,7 @@ py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht) } } if (digest == NULL) { - _setException(PyExc_ValueError, "unsupported hash type %s", name); + _setException(state->unsupported_digestmod_error, "unsupported hash type %s", name); return NULL; } return digest; From webhook-mailer at python.org Fri Apr 7 05:23:17 2023 From: webhook-mailer at python.org (Fidget-Spinner) Date: Fri, 07 Apr 2023 09:23:17 -0000 Subject: [Python-checkins] gh-102213: Revert "gh-102213: Optimize the performance of `__getattr__` (GH-102248)" (GH-103332) Message-ID: https://github.com/python/cpython/commit/059bb04245a8b3490f93dfd72522a431a113eef1 commit: 059bb04245a8b3490f93dfd72522a431a113eef1 branch: main author: Nikita Sobolev committer: Fidget-Spinner date: 2023-04-07T17:22:36+08:00 summary: gh-102213: Revert "gh-102213: Optimize the performance of `__getattr__` (GH-102248)" (GH-103332) This reverts commit aa0a73d1bc53dcb6348a869df1e775138991e561. files: M Include/internal/pycore_object.h M Objects/object.c M Objects/typeobject.c diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index e18e787449c2..b3d496ed6fc2 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -375,7 +375,6 @@ extern void _PyObject_FreeInstanceAttributes(PyObject *obj); extern int _PyObject_IsInstanceDictEmpty(PyObject *); extern int _PyType_HasSubclasses(PyTypeObject *); extern PyObject* _PyType_GetSubclasses(PyTypeObject *); -extern PyObject* _PyObject_GenericTryGetAttr(PyObject *, PyObject *); // Access macro to the members which are floating "behind" the object static inline PyMemberDef* _PyHeapType_GET_MEMBERS(PyHeapTypeObject *etype) { diff --git a/Objects/object.c b/Objects/object.c index 9dd5eb998217..71f098eed37f 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1491,12 +1491,6 @@ PyObject_GenericGetAttr(PyObject *obj, PyObject *name) return _PyObject_GenericGetAttrWithDict(obj, name, NULL, 0); } -PyObject * -_PyObject_GenericTryGetAttr(PyObject *obj, PyObject *name) -{ - return _PyObject_GenericGetAttrWithDict(obj, name, NULL, 1); -} - int _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name, PyObject *value, PyObject *dict) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 24541bddbbc3..995547e7915f 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -8274,17 +8274,14 @@ _Py_slot_tp_getattr_hook(PyObject *self, PyObject *name) (Py_IS_TYPE(getattribute, &PyWrapperDescr_Type) && ((PyWrapperDescrObject *)getattribute)->d_wrapped == (void *)PyObject_GenericGetAttr)) - /* finding nothing is reasonable when __getattr__ is defined */ - res = _PyObject_GenericTryGetAttr(self, name); + res = PyObject_GenericGetAttr(self, name); else { Py_INCREF(getattribute); res = call_attribute(self, getattribute, name); Py_DECREF(getattribute); } - if (res == NULL) { - if (PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Clear(); - } + if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); res = call_attribute(self, getattr, name); } Py_DECREF(getattr); From webhook-mailer at python.org Fri Apr 7 06:43:48 2023 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Apr 2023 10:43:48 -0000 Subject: [Python-checkins] bpo-46523: fix tests rerun when `setUp[Class|Module]` fails (#30895) Message-ID: https://github.com/python/cpython/commit/995386071f96e4cfebfa027a71ca9134e4651d2a commit: 995386071f96e4cfebfa027a71ca9134e4651d2a branch: main author: Nikita Sobolev committer: ambv date: 2023-04-07T12:43:41+02:00 summary: bpo-46523: fix tests rerun when `setUp[Class|Module]` fails (#30895) Co-authored-by: Jelle Zijlstra Co-authored-by: ?ukasz Langa files: M Lib/test/libregrtest/main.py M Lib/test/support/__init__.py M Lib/test/test_regrtest.py diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py index 19ccf2db5e7f..3c3509d03033 100644 --- a/Lib/test/libregrtest/main.py +++ b/Lib/test/libregrtest/main.py @@ -29,6 +29,14 @@ # Must be smaller than buildbot "1200 seconds without output" limit. EXIT_TIMEOUT = 120.0 +# gh-90681: When rerunning tests, we might need to rerun the whole +# class or module suite if some its life-cycle hooks fail. +# Test level hooks are not affected. +_TEST_LIFECYCLE_HOOKS = frozenset(( + 'setUpClass', 'tearDownClass', + 'setUpModule', 'tearDownModule', +)) + EXITCODE_BAD_TEST = 2 EXITCODE_INTERRUPTED = 130 EXITCODE_ENV_CHANGED = 3 @@ -337,8 +345,12 @@ def rerun_failed_tests(self): errors = result.errors or [] failures = result.failures or [] - error_names = [test_full_name.split(" ")[0] for (test_full_name, *_) in errors] - failure_names = [test_full_name.split(" ")[0] for (test_full_name, *_) in failures] + error_names = [ + self.normalize_test_name(test_full_name, is_error=True) + for (test_full_name, *_) in errors] + failure_names = [ + self.normalize_test_name(test_full_name) + for (test_full_name, *_) in failures] self.ns.verbose = True orig_match_tests = self.ns.match_tests if errors or failures: @@ -364,6 +376,21 @@ def rerun_failed_tests(self): self.display_result() + def normalize_test_name(self, test_full_name, *, is_error=False): + short_name = test_full_name.split(" ")[0] + if is_error and short_name in _TEST_LIFECYCLE_HOOKS: + # This means that we have a failure in a life-cycle hook, + # we need to rerun the whole module or class suite. + # Basically the error looks like this: + # ERROR: setUpClass (test.test_reg_ex.RegTest) + # or + # ERROR: setUpModule (test.test_reg_ex) + # So, we need to parse the class / module name. + lpar = test_full_name.index('(') + rpar = test_full_name.index(')') + return test_full_name[lpar + 1: rpar].split('.')[-1] + return short_name + def display_result(self): # If running the test suite for PGO then no one cares about results. if self.ns.pgo: diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index c309fd7910e0..d063837baee2 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -1108,7 +1108,7 @@ def _run_suite(suite): if junit_xml_list is not None: junit_xml_list.append(result.get_xml_element()) - if not result.testsRun and not result.skipped: + if not result.testsRun and not result.skipped and not result.errors: raise TestDidNotRun if not result.wasSuccessful(): if len(result.errors) == 1 and not result.failures: diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index baae4efc2ad7..ac49fbae8477 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -1120,6 +1120,160 @@ def test_fail_once(self): self.check_executed_tests(output, [testname], rerun={testname: "test_fail_once"}) + def test_rerun_setup_class_hook_failure(self): + # FAILURE then FAILURE + code = textwrap.dedent(""" + import unittest + + class ExampleTests(unittest.TestCase): + @classmethod + def setUpClass(self): + raise RuntimeError('Fail') + + def test_success(self): + return + """) + testname = self.create_test(code=code) + + output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, testname, + failed=[testname], + rerun={testname: "ExampleTests"}) + + def test_rerun_teardown_class_hook_failure(self): + # FAILURE then FAILURE + code = textwrap.dedent(""" + import unittest + + class ExampleTests(unittest.TestCase): + @classmethod + def tearDownClass(self): + raise RuntimeError('Fail') + + def test_success(self): + return + """) + testname = self.create_test(code=code) + + output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, testname, + failed=[testname], + rerun={testname: "ExampleTests"}) + + def test_rerun_setup_module_hook_failure(self): + # FAILURE then FAILURE + code = textwrap.dedent(""" + import unittest + + def setUpModule(): + raise RuntimeError('Fail') + + class ExampleTests(unittest.TestCase): + def test_success(self): + return + """) + testname = self.create_test(code=code) + + output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, testname, + failed=[testname], + rerun={testname: testname}) + + def test_rerun_teardown_module_hook_failure(self): + # FAILURE then FAILURE + code = textwrap.dedent(""" + import unittest + + def tearDownModule(): + raise RuntimeError('Fail') + + class ExampleTests(unittest.TestCase): + def test_success(self): + return + """) + testname = self.create_test(code=code) + + output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, testname, + failed=[testname], + rerun={testname: testname}) + + def test_rerun_setup_hook_failure(self): + # FAILURE then FAILURE + code = textwrap.dedent(""" + import unittest + + class ExampleTests(unittest.TestCase): + def setUp(self): + raise RuntimeError('Fail') + + def test_success(self): + return + """) + testname = self.create_test(code=code) + + output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, testname, + failed=[testname], + rerun={testname: "test_success"}) + + def test_rerun_teardown_hook_failure(self): + # FAILURE then FAILURE + code = textwrap.dedent(""" + import unittest + + class ExampleTests(unittest.TestCase): + def tearDown(self): + raise RuntimeError('Fail') + + def test_success(self): + return + """) + testname = self.create_test(code=code) + + output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, testname, + failed=[testname], + rerun={testname: "test_success"}) + + def test_rerun_async_setup_hook_failure(self): + # FAILURE then FAILURE + code = textwrap.dedent(""" + import unittest + + class ExampleTests(unittest.IsolatedAsyncioTestCase): + async def asyncSetUp(self): + raise RuntimeError('Fail') + + async def test_success(self): + return + """) + testname = self.create_test(code=code) + + output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, testname, + failed=[testname], + rerun={testname: "test_success"}) + + def test_rerun_async_teardown_hook_failure(self): + # FAILURE then FAILURE + code = textwrap.dedent(""" + import unittest + + class ExampleTests(unittest.IsolatedAsyncioTestCase): + async def asyncTearDown(self): + raise RuntimeError('Fail') + + async def test_success(self): + return + """) + testname = self.create_test(code=code) + + output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, testname, + failed=[testname], + rerun={testname: "test_success"}) + def test_no_tests_ran(self): code = textwrap.dedent(""" import unittest From webhook-mailer at python.org Fri Apr 7 07:56:08 2023 From: webhook-mailer at python.org (barneygale) Date: Fri, 07 Apr 2023 11:56:08 -0000 Subject: [Python-checkins] GH-88013: Fix TypeError raised by ntpath.realpath in some cases (GH-102813) Message-ID: https://github.com/python/cpython/commit/4dc339b4d69195448207e1faecc3e258700daf33 commit: 4dc339b4d69195448207e1faecc3e258700daf33 branch: main author: AN Long committer: barneygale date: 2023-04-07T12:56:00+01:00 summary: GH-88013: Fix TypeError raised by ntpath.realpath in some cases (GH-102813) files: A Misc/NEWS.d/next/Windows/2023-03-18-21-38-00.gh-issue-88013.Z3loxC.rst M Lib/ntpath.py M Lib/test/test_ntpath.py diff --git a/Lib/ntpath.py b/Lib/ntpath.py index e93a5e696009..6e2da79c85d3 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -670,7 +670,7 @@ def _getfinalpathname_nonstrict(path): # Non-strict algorithm is to find as much of the target directory # as we can and join the rest. - tail = '' + tail = path[:0] while path: try: path = _getfinalpathname(path) diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index 08c8a7a1f94b..4e755d154039 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -1,6 +1,7 @@ import inspect import ntpath import os +import string import sys import unittest import warnings @@ -374,6 +375,12 @@ def test_realpath_basic(self): self.assertPathEqual(ntpath.realpath(os.fsencode(ABSTFN + "1")), os.fsencode(ABSTFN)) + # gh-88013: call ntpath.realpath with binary drive name may raise a + # TypeError. The drive should not exist to reproduce the bug. + drives = {f"{c}:\\" for c in string.ascii_uppercase} - set(os.listdrives()) + d = drives.pop().encode() + self.assertEqual(ntpath.realpath(d), d) + @os_helper.skip_unless_symlink @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') def test_realpath_strict(self): diff --git a/Misc/NEWS.d/next/Windows/2023-03-18-21-38-00.gh-issue-88013.Z3loxC.rst b/Misc/NEWS.d/next/Windows/2023-03-18-21-38-00.gh-issue-88013.Z3loxC.rst new file mode 100644 index 000000000000..4ca3185ea1f6 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-03-18-21-38-00.gh-issue-88013.Z3loxC.rst @@ -0,0 +1,2 @@ +Fixed a bug where :exc:`TypeError` was raised when calling +:func:`ntpath.realpath` with a bytes parameter in some cases. From webhook-mailer at python.org Fri Apr 7 13:15:05 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Fri, 07 Apr 2023 17:15:05 -0000 Subject: [Python-checkins] gh-103193: Celebrate performance improvements to `inspect.getattr_static` in 'What's New in Python 3.12' (#103349) Message-ID: https://github.com/python/cpython/commit/04501ee57e7f6ef216b15b45785285fe4acebc42 commit: 04501ee57e7f6ef216b15b45785285fe4acebc42 branch: main author: Alex Waygood committer: AlexWaygood date: 2023-04-07T18:14:50+01:00 summary: gh-103193: Celebrate performance improvements to `inspect.getattr_static` in 'What's New in Python 3.12' (#103349) files: M Doc/whatsnew/3.12.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 23524ec5d7d4..3a12fb20c43c 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -255,6 +255,10 @@ inspect for determining the current state of asynchronous generators. (Contributed by Thomas Krennwallner in :issue:`35759`.) +* The performance of :func:`inspect.getattr_static` has been considerably + improved. Most calls to the function should be around 2x faster than they + were in Python 3.11. (Contributed by Alex Waygood in :gh:`103193`.) + pathlib ------- From webhook-mailer at python.org Fri Apr 7 13:21:26 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Fri, 07 Apr 2023 17:21:26 -0000 Subject: [Python-checkins] gh-74690: Add more tests for runtime-checkable protocols (#103347) Message-ID: https://github.com/python/cpython/commit/800382a2b0980c21dfb2a8ac02aaf1e881f987b9 commit: 800382a2b0980c21dfb2a8ac02aaf1e881f987b9 branch: main author: Alex Waygood committer: AlexWaygood date: 2023-04-07T18:21:19+01:00 summary: gh-74690: Add more tests for runtime-checkable protocols (#103347) files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 7d2e6a6a9f62..b8eee9a570a3 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2577,6 +2577,22 @@ def meth(x): ... class PG(Protocol[T]): def meth(x): ... + @runtime_checkable + class WeirdProto(Protocol): + meth = str.maketrans + + @runtime_checkable + class WeirdProto2(Protocol): + meth = lambda *args, **kwargs: None + + class CustomCallable: + def __call__(self, *args, **kwargs): + pass + + @runtime_checkable + class WeirderProto(Protocol): + meth = CustomCallable() + class BadP(Protocol): def meth(x): ... @@ -2586,8 +2602,15 @@ def meth(x): ... class C: def meth(x): ... - self.assertIsInstance(C(), P) - self.assertIsInstance(C(), PG) + class C2: + def __init__(self): + self.meth = lambda: None + + for klass in C, C2: + for proto in P, PG, WeirdProto, WeirdProto2, WeirderProto: + with self.subTest(klass=klass.__name__, proto=proto.__name__): + self.assertIsInstance(klass(), proto) + with self.assertRaises(TypeError): isinstance(C(), PG[T]) with self.assertRaises(TypeError): @@ -2829,6 +2852,20 @@ def __init__(self, x): self.assertIsInstance(C(1), P) self.assertIsInstance(C(1), PG) + def test_protocols_isinstance_monkeypatching(self): + @runtime_checkable + class HasX(Protocol): + x: int + + class Foo: ... + + f = Foo() + self.assertNotIsInstance(f, HasX) + f.x = 42 + self.assertIsInstance(f, HasX) + del f.x + self.assertNotIsInstance(f, HasX) + def test_protocol_checks_after_subscript(self): class P(Protocol[T]): pass class C(P[T]): pass From webhook-mailer at python.org Fri Apr 7 13:35:24 2023 From: webhook-mailer at python.org (ambv) Date: Fri, 07 Apr 2023 17:35:24 -0000 Subject: [Python-checkins] [3.11] bpo-46523: fix tests rerun when `setUp[Class|Module]` fails (GH-30895) (GH-103342) Message-ID: https://github.com/python/cpython/commit/ecb09a849689764193e0115d27e220f82b5f6d9f commit: ecb09a849689764193e0115d27e220f82b5f6d9f branch: 3.11 author: ?ukasz Langa committer: ambv date: 2023-04-07T19:35:16+02:00 summary: [3.11] bpo-46523: fix tests rerun when `setUp[Class|Module]` fails (GH-30895) (GH-103342) (cherry picked from commit 995386071f96e4cfebfa027a71ca9134e4651d2a) Co-authored-by: Nikita Sobolev files: M Lib/test/libregrtest/main.py M Lib/test/support/__init__.py M Lib/test/test_regrtest.py diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py index 655e4d2e56f8..0125227bf117 100644 --- a/Lib/test/libregrtest/main.py +++ b/Lib/test/libregrtest/main.py @@ -28,6 +28,19 @@ # Must be smaller than buildbot "1200 seconds without output" limit. EXIT_TIMEOUT = 120.0 +# gh-90681: When rerunning tests, we might need to rerun the whole +# class or module suite if some its life-cycle hooks fail. +# Test level hooks are not affected. +_TEST_LIFECYCLE_HOOKS = frozenset(( + 'setUpClass', 'tearDownClass', + 'setUpModule', 'tearDownModule', +)) + +EXITCODE_BAD_TEST = 2 +EXITCODE_INTERRUPTED = 130 +EXITCODE_ENV_CHANGED = 3 +EXITCODE_NO_TESTS_RAN = 4 + class Regrtest: """Execute a test suite. @@ -331,8 +344,12 @@ def rerun_failed_tests(self): errors = result.errors or [] failures = result.failures or [] - error_names = [test_full_name.split(" ")[0] for (test_full_name, *_) in errors] - failure_names = [test_full_name.split(" ")[0] for (test_full_name, *_) in failures] + error_names = [ + self.normalize_test_name(test_full_name, is_error=True) + for (test_full_name, *_) in errors] + failure_names = [ + self.normalize_test_name(test_full_name) + for (test_full_name, *_) in failures] self.ns.verbose = True orig_match_tests = self.ns.match_tests if errors or failures: @@ -358,6 +375,21 @@ def rerun_failed_tests(self): self.display_result() + def normalize_test_name(self, test_full_name, *, is_error=False): + short_name = test_full_name.split(" ")[0] + if is_error and short_name in _TEST_LIFECYCLE_HOOKS: + # This means that we have a failure in a life-cycle hook, + # we need to rerun the whole module or class suite. + # Basically the error looks like this: + # ERROR: setUpClass (test.test_reg_ex.RegTest) + # or + # ERROR: setUpModule (test.test_reg_ex) + # So, we need to parse the class / module name. + lpar = test_full_name.index('(') + rpar = test_full_name.index(')') + return test_full_name[lpar + 1: rpar].split('.')[-1] + return short_name + def display_result(self): # If running the test suite for PGO then no one cares about results. if self.ns.pgo: diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index c33f90d8071d..98be9cdd0e16 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -1097,7 +1097,7 @@ def _run_suite(suite): if junit_xml_list is not None: junit_xml_list.append(result.get_xml_element()) - if not result.testsRun and not result.skipped: + if not result.testsRun and not result.skipped and not result.errors: raise TestDidNotRun if not result.wasSuccessful(): if len(result.errors) == 1 and not result.failures: diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 15e2f89ee20c..f692dd1e3e65 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -30,6 +30,11 @@ ROOT_DIR = os.path.abspath(os.path.normpath(ROOT_DIR)) LOG_PREFIX = r'[0-9]+:[0-9]+:[0-9]+ (?:load avg: [0-9]+\.[0-9]{2} )?' +EXITCODE_BAD_TEST = 2 +EXITCODE_ENV_CHANGED = 3 +EXITCODE_NO_TESTS_RAN = 4 +EXITCODE_INTERRUPTED = 130 + TEST_INTERRUPTED = textwrap.dedent(""" from signal import SIGINT, raise_signal try: @@ -1115,6 +1120,160 @@ def test_fail_once(self): self.check_executed_tests(output, [testname], rerun={testname: "test_fail_once"}) + def test_rerun_setup_class_hook_failure(self): + # FAILURE then FAILURE + code = textwrap.dedent(""" + import unittest + + class ExampleTests(unittest.TestCase): + @classmethod + def setUpClass(self): + raise RuntimeError('Fail') + + def test_success(self): + return + """) + testname = self.create_test(code=code) + + output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, testname, + failed=[testname], + rerun={testname: "ExampleTests"}) + + def test_rerun_teardown_class_hook_failure(self): + # FAILURE then FAILURE + code = textwrap.dedent(""" + import unittest + + class ExampleTests(unittest.TestCase): + @classmethod + def tearDownClass(self): + raise RuntimeError('Fail') + + def test_success(self): + return + """) + testname = self.create_test(code=code) + + output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, testname, + failed=[testname], + rerun={testname: "ExampleTests"}) + + def test_rerun_setup_module_hook_failure(self): + # FAILURE then FAILURE + code = textwrap.dedent(""" + import unittest + + def setUpModule(): + raise RuntimeError('Fail') + + class ExampleTests(unittest.TestCase): + def test_success(self): + return + """) + testname = self.create_test(code=code) + + output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, testname, + failed=[testname], + rerun={testname: testname}) + + def test_rerun_teardown_module_hook_failure(self): + # FAILURE then FAILURE + code = textwrap.dedent(""" + import unittest + + def tearDownModule(): + raise RuntimeError('Fail') + + class ExampleTests(unittest.TestCase): + def test_success(self): + return + """) + testname = self.create_test(code=code) + + output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, testname, + failed=[testname], + rerun={testname: testname}) + + def test_rerun_setup_hook_failure(self): + # FAILURE then FAILURE + code = textwrap.dedent(""" + import unittest + + class ExampleTests(unittest.TestCase): + def setUp(self): + raise RuntimeError('Fail') + + def test_success(self): + return + """) + testname = self.create_test(code=code) + + output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, testname, + failed=[testname], + rerun={testname: "test_success"}) + + def test_rerun_teardown_hook_failure(self): + # FAILURE then FAILURE + code = textwrap.dedent(""" + import unittest + + class ExampleTests(unittest.TestCase): + def tearDown(self): + raise RuntimeError('Fail') + + def test_success(self): + return + """) + testname = self.create_test(code=code) + + output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, testname, + failed=[testname], + rerun={testname: "test_success"}) + + def test_rerun_async_setup_hook_failure(self): + # FAILURE then FAILURE + code = textwrap.dedent(""" + import unittest + + class ExampleTests(unittest.IsolatedAsyncioTestCase): + async def asyncSetUp(self): + raise RuntimeError('Fail') + + async def test_success(self): + return + """) + testname = self.create_test(code=code) + + output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, testname, + failed=[testname], + rerun={testname: "test_success"}) + + def test_rerun_async_teardown_hook_failure(self): + # FAILURE then FAILURE + code = textwrap.dedent(""" + import unittest + + class ExampleTests(unittest.IsolatedAsyncioTestCase): + async def asyncTearDown(self): + raise RuntimeError('Fail') + + async def test_success(self): + return + """) + testname = self.create_test(code=code) + + output = self.run_tests("-w", testname, exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, testname, + failed=[testname], + rerun={testname: "test_success"}) + def test_no_tests_ran(self): code = textwrap.dedent(""" import unittest From webhook-mailer at python.org Fri Apr 7 13:47:56 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Apr 2023 17:47:56 -0000 Subject: [Python-checkins] gh-74690: Add more tests for runtime-checkable protocols (GH-103347) Message-ID: https://github.com/python/cpython/commit/1b1f0164cb210abc0af5803bee071d67e8272bb8 commit: 1b1f0164cb210abc0af5803bee071d67e8272bb8 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-07T10:47:49-07:00 summary: gh-74690: Add more tests for runtime-checkable protocols (GH-103347) (cherry picked from commit 800382a2b0980c21dfb2a8ac02aaf1e881f987b9) Co-authored-by: Alex Waygood files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 4de24472c2c0..46cff6ad5085 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2572,6 +2572,22 @@ def meth(x): ... class PG(Protocol[T]): def meth(x): ... + @runtime_checkable + class WeirdProto(Protocol): + meth = str.maketrans + + @runtime_checkable + class WeirdProto2(Protocol): + meth = lambda *args, **kwargs: None + + class CustomCallable: + def __call__(self, *args, **kwargs): + pass + + @runtime_checkable + class WeirderProto(Protocol): + meth = CustomCallable() + class BadP(Protocol): def meth(x): ... @@ -2581,8 +2597,15 @@ def meth(x): ... class C: def meth(x): ... - self.assertIsInstance(C(), P) - self.assertIsInstance(C(), PG) + class C2: + def __init__(self): + self.meth = lambda: None + + for klass in C, C2: + for proto in P, PG, WeirdProto, WeirdProto2, WeirderProto: + with self.subTest(klass=klass.__name__, proto=proto.__name__): + self.assertIsInstance(klass(), proto) + with self.assertRaises(TypeError): isinstance(C(), PG[T]) with self.assertRaises(TypeError): @@ -2735,6 +2758,20 @@ def __init__(self, x): self.assertIsInstance(C(1), P) self.assertIsInstance(C(1), PG) + def test_protocols_isinstance_monkeypatching(self): + @runtime_checkable + class HasX(Protocol): + x: int + + class Foo: ... + + f = Foo() + self.assertNotIsInstance(f, HasX) + f.x = 42 + self.assertIsInstance(f, HasX) + del f.x + self.assertNotIsInstance(f, HasX) + def test_protocol_checks_after_subscript(self): class P(Protocol[T]): pass class C(P[T]): pass From webhook-mailer at python.org Fri Apr 7 13:57:53 2023 From: webhook-mailer at python.org (iritkatriel) Date: Fri, 07 Apr 2023 17:57:53 -0000 Subject: [Python-checkins] gh-103225: Fixed zero lineno issue for pdb (#103265) Message-ID: https://github.com/python/cpython/commit/2667452945eb0a3b8993bb4298ca8da54dc0155a commit: 2667452945eb0a3b8993bb4298ca8da54dc0155a branch: main author: Tian Gao committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-04-07T18:57:46+01:00 summary: gh-103225: Fixed zero lineno issue for pdb (#103265) Co-authored-by: Artem Mukhin files: A Misc/NEWS.d/next/Library/2023-04-05-01-28-53.gh-issue-103225.QD3JVU.rst M Lib/pdb.py M Lib/test/test_pdb.py diff --git a/Lib/pdb.py b/Lib/pdb.py index 3a06cd00ad2b..e043b0d46f7d 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1351,7 +1351,7 @@ def do_longlist(self, arg): filename = self.curframe.f_code.co_filename breaklist = self.get_file_breaks(filename) try: - lines, lineno = inspect.getsourcelines(self.curframe) + lines, lineno = self._getsourcelines(self.curframe) except OSError as err: self.error(err) return @@ -1367,7 +1367,7 @@ def do_source(self, arg): except: return try: - lines, lineno = inspect.getsourcelines(obj) + lines, lineno = self._getsourcelines(obj) except (OSError, TypeError) as err: self.error(err) return @@ -1662,6 +1662,16 @@ def _compile_error_message(self, expr): return _rstr(self._format_exc(exc)) return "" + def _getsourcelines(self, obj): + # GH-103319 + # inspect.getsourcelines() returns lineno = 0 for + # module-level frame which breaks our code print line number + # This method should be replaced by inspect.getsourcelines(obj) + # once this bug is fixed in inspect + lines, lineno = inspect.getsourcelines(obj) + lineno = max(1, lineno) + return lines, lineno + # Collect all command help into docstring, if not run with -OO if __doc__ is not None: diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index de2bab464957..9ad9a1c52ac1 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1675,6 +1675,31 @@ def test_pdb_issue_gh_101673(): (Pdb) continue """ +def test_pdb_issue_gh_103225(): + """See GH-103225 + + Make sure longlist uses 1-based line numbers in frames that correspond to a module + + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE + ... 'longlist', + ... 'continue' + ... ]): + ... a = 1 + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... b = 2 + > (7)() + -> b = 2 + (Pdb) longlist + 1 with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE + 2 'longlist', + 3 'continue' + 4 ]): + 5 a = 1 + 6 import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + 7 -> b = 2 + (Pdb) continue + """ + @support.requires_subprocess() class PdbTestCase(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-04-05-01-28-53.gh-issue-103225.QD3JVU.rst b/Misc/NEWS.d/next/Library/2023-04-05-01-28-53.gh-issue-103225.QD3JVU.rst new file mode 100644 index 000000000000..5d1a063acdeb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-05-01-28-53.gh-issue-103225.QD3JVU.rst @@ -0,0 +1 @@ +Fix a bug in :mod:`pdb` when displaying line numbers of module-level source code. From webhook-mailer at python.org Fri Apr 7 14:24:07 2023 From: webhook-mailer at python.org (zware) Date: Fri, 07 Apr 2023 18:24:07 -0000 Subject: [Python-checkins] gh-100220: Fix error handling in make rules (GH-100328) Message-ID: https://github.com/python/cpython/commit/a90863c993157ae65e040476cf46abd73ae54b4a commit: a90863c993157ae65e040476cf46abd73ae54b4a branch: main author: Micha? G?rny committer: zware date: 2023-04-07T13:23:59-05:00 summary: gh-100220: Fix error handling in make rules (GH-100328) Set `SHELL = /bin/sh -e` to ensure that complex recipes fail on the first error rather than incorrectly reporting success. Co-authored-by: Zachary Ware files: A Misc/NEWS.d/next/Build/2022-12-18-07-24-44.gh-issue-100220.BgSV7C.rst M Makefile.pre.in diff --git a/Makefile.pre.in b/Makefile.pre.in index 1c1bddcad824..fefa5d4e8147 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -59,7 +59,7 @@ DSYMUTIL_PATH= @DSYMUTIL_PATH@ GNULD= @GNULD@ # Shell used by make (some versions default to the login shell, which is bad) -SHELL= /bin/sh +SHELL= /bin/sh -e # Use this to make a link between python$(VERSION) and python in $(BINDIR) LN= @LN@ diff --git a/Misc/NEWS.d/next/Build/2022-12-18-07-24-44.gh-issue-100220.BgSV7C.rst b/Misc/NEWS.d/next/Build/2022-12-18-07-24-44.gh-issue-100220.BgSV7C.rst new file mode 100644 index 000000000000..7135317cd06f --- /dev/null +++ b/Misc/NEWS.d/next/Build/2022-12-18-07-24-44.gh-issue-100220.BgSV7C.rst @@ -0,0 +1,4 @@ +Changed the default value of the ``SHELL`` Makefile variable from ``/bin/sh`` +to ``/bin/sh -e`` to ensure that complex recipes correctly fail after an error. +Previously, ``make install`` could fail to install some files and yet return +a successful result. From webhook-mailer at python.org Fri Apr 7 15:11:18 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Fri, 07 Apr 2023 19:11:18 -0000 Subject: [Python-checkins] gh-103272: regression test for getattr exception in property (#103336) Message-ID: https://github.com/python/cpython/commit/5d7d86f2fdbbfc23325e7256ee289bf20ce7124e commit: 5d7d86f2fdbbfc23325e7256ee289bf20ce7124e branch: main author: sunmy2019 <59365878+sunmy2019 at users.noreply.github.com> committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-04-07T12:11:11-07:00 summary: gh-103272: regression test for getattr exception in property (#103336) files: M Lib/test/test_descr.py diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index cbc020d1d390..f17bb1813b9d 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -5003,6 +5003,19 @@ class Child(Parent): gc.collect() self.assertEqual(Parent.__subclasses__(), []) + def test_attr_raise_through_property(self): + # add test case for gh-103272 + class A: + def __getattr__(self, name): + raise ValueError("FOO") + + @property + def foo(self): + return self.__getattr__("asdf") + + with self.assertRaisesRegex(ValueError, "FOO"): + A().foo + class DictProxyTests(unittest.TestCase): def setUp(self): From webhook-mailer at python.org Fri Apr 7 15:36:22 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Apr 2023 19:36:22 -0000 Subject: [Python-checkins] gh-103272: regression test for getattr exception in property (GH-103336) Message-ID: https://github.com/python/cpython/commit/b8d1623f73031ebfedf3531a44f4a05730c45320 commit: b8d1623f73031ebfedf3531a44f4a05730c45320 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-07T12:36:10-07:00 summary: gh-103272: regression test for getattr exception in property (GH-103336) (cherry picked from commit 5d7d86f2fdbbfc23325e7256ee289bf20ce7124e) Co-authored-by: sunmy2019 <59365878+sunmy2019 at users.noreply.github.com> files: M Lib/test/test_descr.py diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 3145dff81b4d..f07d7d459659 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4999,6 +4999,19 @@ class Child(Parent): gc.collect() self.assertEqual(Parent.__subclasses__(), []) + def test_attr_raise_through_property(self): + # add test case for gh-103272 + class A: + def __getattr__(self, name): + raise ValueError("FOO") + + @property + def foo(self): + return self.__getattr__("asdf") + + with self.assertRaisesRegex(ValueError, "FOO"): + A().foo + class DictProxyTests(unittest.TestCase): def setUp(self): From webhook-mailer at python.org Fri Apr 7 16:39:03 2023 From: webhook-mailer at python.org (barneygale) Date: Fri, 07 Apr 2023 20:39:03 -0000 Subject: [Python-checkins] [3.11] GH-88013: Fix TypeError raised by ntpath.realpath in some cases (GH-102813, GH-103343) Message-ID: https://github.com/python/cpython/commit/70bc8c936dfbd936959efd32f0cddc2597598592 commit: 70bc8c936dfbd936959efd32f0cddc2597598592 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: barneygale date: 2023-04-07T21:38:56+01:00 summary: [3.11] GH-88013: Fix TypeError raised by ntpath.realpath in some cases (GH-102813, GH-103343) (cherry picked from commit 4dc339b4d69195448207e1faecc3e258700daf33) Co-authored-by: AN Long Co-authored-by: Barney Gale files: A Misc/NEWS.d/next/Windows/2023-03-18-21-38-00.gh-issue-88013.Z3loxC.rst M Lib/ntpath.py M Lib/test/test_ntpath.py diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 1cfb15b77102..0444b0f65d10 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -644,7 +644,7 @@ def _getfinalpathname_nonstrict(path): # Non-strict algorithm is to find as much of the target directory # as we can and join the rest. - tail = '' + tail = path[:0] while path: try: path = _getfinalpathname(path) diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index c26c74cdd619..646e81d1e2fa 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -1,5 +1,6 @@ import ntpath import os +import string import sys import unittest import warnings @@ -321,6 +322,16 @@ def test_realpath_basic(self): self.assertPathEqual(ntpath.realpath(os.fsencode(ABSTFN + "1")), os.fsencode(ABSTFN)) + # gh-88013: call ntpath.realpath with binary drive name may raise a + # TypeError. The drive should not exist to reproduce the bug. + for c in string.ascii_uppercase: + d = f"{c}:\\" + if not ntpath.exists(d): + break + else: + raise OSError("No free drive letters available") + self.assertEqual(ntpath.realpath(d), d) + @os_helper.skip_unless_symlink @unittest.skipUnless(HAVE_GETFINALPATHNAME, 'need _getfinalpathname') def test_realpath_strict(self): diff --git a/Misc/NEWS.d/next/Windows/2023-03-18-21-38-00.gh-issue-88013.Z3loxC.rst b/Misc/NEWS.d/next/Windows/2023-03-18-21-38-00.gh-issue-88013.Z3loxC.rst new file mode 100644 index 000000000000..4ca3185ea1f6 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-03-18-21-38-00.gh-issue-88013.Z3loxC.rst @@ -0,0 +1,2 @@ +Fixed a bug where :exc:`TypeError` was raised when calling +:func:`ntpath.realpath` with a bytes parameter in some cases. From webhook-mailer at python.org Fri Apr 7 17:06:44 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Fri, 07 Apr 2023 21:06:44 -0000 Subject: [Python-checkins] gh-74690: Document changes made to runtime-checkable protocols in 3.12 (#103348) Message-ID: https://github.com/python/cpython/commit/644136563da653a93268cb8cae7e25ff691047a3 commit: 644136563da653a93268cb8cae7e25ff691047a3 branch: main author: Alex Waygood committer: AlexWaygood date: 2023-04-07T22:06:37+01:00 summary: gh-74690: Document changes made to runtime-checkable protocols in 3.12 (#103348) Co-authored-by: Jelle Zijlstra files: A Misc/NEWS.d/next/Library/2023-04-07-15-09-26.gh-issue-74690.0f886b.rst A Misc/NEWS.d/next/Library/2023-04-07-15-15-40.gh-issue-74690.un84hh.rst M Doc/library/typing.rst M Doc/whatsnew/3.12.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 8728ca7b6b35..03ff259bbdf7 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1598,15 +1598,6 @@ These are not used in annotations. They are building blocks for creating generic import threading assert isinstance(threading.Thread(name='Bob'), Named) - .. versionchanged:: 3.12 - The internal implementation of :func:`isinstance` checks against - runtime-checkable protocols now uses :func:`inspect.getattr_static` - to look up attributes (previously, :func:`hasattr` was used). - As a result, some objects which used to be considered instances - of a runtime-checkable protocol may no longer be considered instances - of that protocol on Python 3.12+, and vice versa. - Most users are unlikely to be affected by this change. - .. note:: :func:`!runtime_checkable` will check only the presence of the required @@ -1628,6 +1619,24 @@ These are not used in annotations. They are building blocks for creating generic .. versionadded:: 3.8 + .. versionchanged:: 3.12 + The internal implementation of :func:`isinstance` checks against + runtime-checkable protocols now uses :func:`inspect.getattr_static` + to look up attributes (previously, :func:`hasattr` was used). + As a result, some objects which used to be considered instances + of a runtime-checkable protocol may no longer be considered instances + of that protocol on Python 3.12+, and vice versa. + Most users are unlikely to be affected by this change. + + .. versionchanged:: 3.12 + The members of a runtime-checkable protocol are now considered "frozen" + at runtime as soon as the class has been created. Monkey-patching + attributes onto a runtime-checkable protocol will still work, but will + have no impact on :func:`isinstance` checks comparing objects to the + protocol. See :ref:`"What's new in Python 3.12" ` + for more details. + + Other special directives """""""""""""""""""""""" diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 3a12fb20c43c..66e40ef7326c 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -422,6 +422,8 @@ tempfile The :class:`tempfile.NamedTemporaryFile` function has a new optional parameter *delete_on_close* (Contributed by Evgeny Zorin in :gh:`58451`.) +.. _whatsnew-typing-py312: + typing ------ @@ -441,6 +443,39 @@ typing vice versa. Most users are unlikely to be affected by this change. (Contributed by Alex Waygood in :gh:`102433`.) +* The members of a runtime-checkable protocol are now considered "frozen" at + runtime as soon as the class has been created. Monkey-patching attributes + onto a runtime-checkable protocol will still work, but will have no impact on + :func:`isinstance` checks comparing objects to the protocol. For example:: + + >>> from typing import Protocol, runtime_checkable + >>> @runtime_checkable + ... class HasX(Protocol): + ... x = 1 + ... + >>> class Foo: ... + ... + >>> f = Foo() + >>> isinstance(f, HasX) + False + >>> f.x = 1 + >>> isinstance(f, HasX) + True + >>> HasX.y = 2 + >>> isinstance(f, HasX) # unchanged, even though HasX now also has a "y" attribute + True + + This change was made in order to speed up ``isinstance()`` checks against + runtime-checkable protocols. + +* The performance profile of :func:`isinstance` checks against + :func:`runtime-checkable protocols ` has changed + significantly. Most ``isinstance()`` checks against protocols with only a few + members should be at least 2x faster than in 3.11, and some may be 20x + faster or more. However, ``isinstance()`` checks against protocols with seven + or more members may be slower than in Python 3.11. (Contributed by Alex + Waygood in :gh:`74690` and :gh:`103193`.) + sys --- diff --git a/Misc/NEWS.d/next/Library/2023-04-07-15-09-26.gh-issue-74690.0f886b.rst b/Misc/NEWS.d/next/Library/2023-04-07-15-09-26.gh-issue-74690.0f886b.rst new file mode 100644 index 000000000000..0a103ae11970 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-07-15-09-26.gh-issue-74690.0f886b.rst @@ -0,0 +1,3 @@ +The members of a runtime-checkable protocol are now considered "frozen" at +runtime as soon as the class has been created. See +:ref:`"What's new in Python 3.12" ` for more details. diff --git a/Misc/NEWS.d/next/Library/2023-04-07-15-15-40.gh-issue-74690.un84hh.rst b/Misc/NEWS.d/next/Library/2023-04-07-15-15-40.gh-issue-74690.un84hh.rst new file mode 100644 index 000000000000..48f11aac692d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-07-15-15-40.gh-issue-74690.un84hh.rst @@ -0,0 +1,8 @@ +The performance of :func:`isinstance` checks against +:func:`runtime-checkable protocols ` has been +considerably improved for protocols that only have a few members. To achieve +this improvement, several internal implementation details of the +:mod:`typing` module have been refactored, including +``typing._ProtocolMeta.__instancecheck__``, +``typing._is_callable_members_only``, and ``typing._get_protocol_attrs``. +Patches by Alex Waygood. From webhook-mailer at python.org Fri Apr 7 19:43:51 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 07 Apr 2023 23:43:51 -0000 Subject: [Python-checkins] gh-83004: Harden _socket init (GH-103261) Message-ID: https://github.com/python/cpython/commit/91794e587306343619a451473efae22aa9f4b9bd commit: 91794e587306343619a451473efae22aa9f4b9bd branch: main author: Erlend E. Aasland committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-07T16:43:44-07:00 summary: gh-83004: Harden _socket init (GH-103261) Automerge-Triggered-By: GH:erlend-aasland files: M Modules/socketmodule.c diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index c2b8283d84e5..49342b3d48de 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -7338,1394 +7338,1427 @@ static struct PyModuleDef socketmodule = { PyMODINIT_FUNC PyInit__socket(void) { - PyObject *m, *has_ipv6; + PyObject *m = NULL; - if (!os_init()) - return NULL; + if (!os_init()) { + goto error; + } Py_SET_TYPE(&sock_type, &PyType_Type); m = PyModule_Create(&socketmodule); - if (m == NULL) - return NULL; + if (m == NULL) { + goto error; + } - PyModule_AddObject(m, "error", Py_NewRef(PyExc_OSError)); - socket_herror = PyErr_NewException("socket.herror", - PyExc_OSError, NULL); - if (socket_herror == NULL) - return NULL; - PyModule_AddObject(m, "herror", Py_NewRef(socket_herror)); - socket_gaierror = PyErr_NewException("socket.gaierror", PyExc_OSError, - NULL); - if (socket_gaierror == NULL) - return NULL; - PyModule_AddObject(m, "gaierror", Py_NewRef(socket_gaierror)); - PyModule_AddObjectRef(m, "timeout", PyExc_TimeoutError); +#define ADD_EXC(MOD, NAME, VAR, BASE) do { \ + VAR = PyErr_NewException("socket." NAME, BASE, NULL); \ + if (VAR == NULL) { \ + goto error; \ + } \ + int rc = PyModule_AddObjectRef(MOD, NAME, VAR); \ + Py_DECREF(VAR); \ + if (rc < 0) { \ + goto error; \ + } \ +} while (0) - if (PyModule_AddObject(m, "SocketType", Py_NewRef(&sock_type)) != 0) - return NULL; - if (PyModule_AddObject(m, "socket", Py_NewRef(&sock_type)) != 0) - return NULL; + ADD_EXC(m, "herror", socket_herror, PyExc_OSError); + ADD_EXC(m, "gaierror", socket_gaierror, PyExc_OSError); +#undef ADD_EXC + + if (PyModule_AddObjectRef(m, "error", PyExc_OSError) < 0) { + goto error; + } + if (PyModule_AddObjectRef(m, "timeout", PyExc_TimeoutError) < 0) { + goto error; + } + if (PyModule_AddObjectRef(m, "SocketType", (PyObject *)&sock_type) < 0) { + goto error; + } + if (PyModule_AddType(m, &sock_type) < 0) { + goto error; + } + + PyObject *has_ipv6; #ifdef ENABLE_IPV6 has_ipv6 = Py_True; #else has_ipv6 = Py_False; #endif - PyModule_AddObject(m, "has_ipv6", Py_NewRef(has_ipv6)); + if (PyModule_AddObjectRef(m, "has_ipv6", has_ipv6) < 0) { + goto error; + } /* Export C API */ PySocketModule_APIObject *capi = sock_get_api(); if (capi == NULL) { - Py_DECREF(m); - return NULL; + goto error; } PyObject *capsule = PyCapsule_New(capi, PySocket_CAPSULE_NAME, sock_destroy_api); if (capsule == NULL) { sock_free_api(capi); - Py_DECREF(m); - return NULL; + goto error; } - if (PyModule_AddObject(m, PySocket_CAPI_NAME, capsule) < 0) { - Py_DECREF(capsule); - Py_DECREF(m); - return NULL; + int rc = PyModule_AddObjectRef(m, PySocket_CAPI_NAME, capsule); + Py_DECREF(capsule); + if (rc < 0) { + goto error; } +#define ADD_INT_MACRO(MOD, INT) do { \ + if (PyModule_AddIntConstant(MOD, #INT, INT) < 0) { \ + goto error; \ + } \ +} while (0) + +#define ADD_INT_CONST(MOD, NAME, INT) do { \ + if (PyModule_AddIntConstant(MOD, NAME, INT) < 0) { \ + goto error; \ + } \ +} while (0) + +#define ADD_STR_CONST(MOD, NAME, STR) do { \ + if (PyModule_AddStringConstant(MOD, NAME, STR) < 0) { \ + goto error; \ + } \ +} while (0) + /* Address families (we only support AF_INET and AF_UNIX) */ #ifdef AF_UNSPEC - PyModule_AddIntMacro(m, AF_UNSPEC); + ADD_INT_MACRO(m, AF_UNSPEC); #endif - PyModule_AddIntMacro(m, AF_INET); + ADD_INT_MACRO(m, AF_INET); #if defined(AF_UNIX) - PyModule_AddIntMacro(m, AF_UNIX); + ADD_INT_MACRO(m, AF_UNIX); #endif /* AF_UNIX */ #ifdef AF_AX25 /* Amateur Radio AX.25 */ - PyModule_AddIntMacro(m, AF_AX25); + ADD_INT_MACRO(m, AF_AX25); #endif #ifdef AF_IPX - PyModule_AddIntMacro(m, AF_IPX); /* Novell IPX */ + ADD_INT_MACRO(m, AF_IPX); /* Novell IPX */ #endif #ifdef AF_APPLETALK /* Appletalk DDP */ - PyModule_AddIntMacro(m, AF_APPLETALK); + ADD_INT_MACRO(m, AF_APPLETALK); #endif #ifdef AF_NETROM /* Amateur radio NetROM */ - PyModule_AddIntMacro(m, AF_NETROM); + ADD_INT_MACRO(m, AF_NETROM); #endif #ifdef AF_BRIDGE /* Multiprotocol bridge */ - PyModule_AddIntMacro(m, AF_BRIDGE); + ADD_INT_MACRO(m, AF_BRIDGE); #endif #ifdef AF_ATMPVC /* ATM PVCs */ - PyModule_AddIntMacro(m, AF_ATMPVC); + ADD_INT_MACRO(m, AF_ATMPVC); #endif #ifdef AF_AAL5 /* Reserved for Werner's ATM */ - PyModule_AddIntMacro(m, AF_AAL5); + ADD_INT_MACRO(m, AF_AAL5); #endif #ifdef HAVE_SOCKADDR_ALG - PyModule_AddIntMacro(m, AF_ALG); /* Linux crypto */ + ADD_INT_MACRO(m, AF_ALG); /* Linux crypto */ #endif #ifdef AF_X25 /* Reserved for X.25 project */ - PyModule_AddIntMacro(m, AF_X25); + ADD_INT_MACRO(m, AF_X25); #endif #ifdef AF_INET6 - PyModule_AddIntMacro(m, AF_INET6); /* IP version 6 */ + ADD_INT_MACRO(m, AF_INET6); /* IP version 6 */ #endif #ifdef AF_ROSE /* Amateur Radio X.25 PLP */ - PyModule_AddIntMacro(m, AF_ROSE); + ADD_INT_MACRO(m, AF_ROSE); #endif #ifdef AF_DECnet /* Reserved for DECnet project */ - PyModule_AddIntMacro(m, AF_DECnet); + ADD_INT_MACRO(m, AF_DECnet); #endif #ifdef AF_NETBEUI /* Reserved for 802.2LLC project */ - PyModule_AddIntMacro(m, AF_NETBEUI); + ADD_INT_MACRO(m, AF_NETBEUI); #endif #ifdef AF_SECURITY /* Security callback pseudo AF */ - PyModule_AddIntMacro(m, AF_SECURITY); + ADD_INT_MACRO(m, AF_SECURITY); #endif #ifdef AF_KEY /* PF_KEY key management API */ - PyModule_AddIntMacro(m, AF_KEY); + ADD_INT_MACRO(m, AF_KEY); #endif #ifdef AF_NETLINK /* */ - PyModule_AddIntMacro(m, AF_NETLINK); - PyModule_AddIntMacro(m, NETLINK_ROUTE); + ADD_INT_MACRO(m, AF_NETLINK); + ADD_INT_MACRO(m, NETLINK_ROUTE); #ifdef NETLINK_SKIP - PyModule_AddIntMacro(m, NETLINK_SKIP); + ADD_INT_MACRO(m, NETLINK_SKIP); #endif #ifdef NETLINK_W1 - PyModule_AddIntMacro(m, NETLINK_W1); + ADD_INT_MACRO(m, NETLINK_W1); #endif - PyModule_AddIntMacro(m, NETLINK_USERSOCK); - PyModule_AddIntMacro(m, NETLINK_FIREWALL); + ADD_INT_MACRO(m, NETLINK_USERSOCK); + ADD_INT_MACRO(m, NETLINK_FIREWALL); #ifdef NETLINK_TCPDIAG - PyModule_AddIntMacro(m, NETLINK_TCPDIAG); + ADD_INT_MACRO(m, NETLINK_TCPDIAG); #endif #ifdef NETLINK_NFLOG - PyModule_AddIntMacro(m, NETLINK_NFLOG); + ADD_INT_MACRO(m, NETLINK_NFLOG); #endif #ifdef NETLINK_XFRM - PyModule_AddIntMacro(m, NETLINK_XFRM); + ADD_INT_MACRO(m, NETLINK_XFRM); #endif #ifdef NETLINK_ARPD - PyModule_AddIntMacro(m, NETLINK_ARPD); + ADD_INT_MACRO(m, NETLINK_ARPD); #endif #ifdef NETLINK_ROUTE6 - PyModule_AddIntMacro(m, NETLINK_ROUTE6); + ADD_INT_MACRO(m, NETLINK_ROUTE6); #endif - PyModule_AddIntMacro(m, NETLINK_IP6_FW); + ADD_INT_MACRO(m, NETLINK_IP6_FW); #ifdef NETLINK_DNRTMSG - PyModule_AddIntMacro(m, NETLINK_DNRTMSG); + ADD_INT_MACRO(m, NETLINK_DNRTMSG); #endif #ifdef NETLINK_TAPBASE - PyModule_AddIntMacro(m, NETLINK_TAPBASE); + ADD_INT_MACRO(m, NETLINK_TAPBASE); #endif #ifdef NETLINK_CRYPTO - PyModule_AddIntMacro(m, NETLINK_CRYPTO); + ADD_INT_MACRO(m, NETLINK_CRYPTO); #endif #endif /* AF_NETLINK */ #ifdef AF_QIPCRTR /* Qualcomm IPCROUTER */ - PyModule_AddIntMacro(m, AF_QIPCRTR); + ADD_INT_MACRO(m, AF_QIPCRTR); #endif #ifdef AF_VSOCK - PyModule_AddIntConstant(m, "AF_VSOCK", AF_VSOCK); - PyModule_AddIntConstant(m, "SO_VM_SOCKETS_BUFFER_SIZE", 0); - PyModule_AddIntConstant(m, "SO_VM_SOCKETS_BUFFER_MIN_SIZE", 1); - PyModule_AddIntConstant(m, "SO_VM_SOCKETS_BUFFER_MAX_SIZE", 2); - PyModule_AddIntConstant(m, "VMADDR_CID_ANY", 0xffffffff); - PyModule_AddIntConstant(m, "VMADDR_PORT_ANY", 0xffffffff); - PyModule_AddIntConstant(m, "VMADDR_CID_HOST", 2); - PyModule_AddIntConstant(m, "VM_SOCKETS_INVALID_VERSION", 0xffffffff); - PyModule_AddIntConstant(m, "IOCTL_VM_SOCKETS_GET_LOCAL_CID", _IO(7, 0xb9)); + ADD_INT_CONST(m, "AF_VSOCK", AF_VSOCK); + ADD_INT_CONST(m, "SO_VM_SOCKETS_BUFFER_SIZE", 0); + ADD_INT_CONST(m, "SO_VM_SOCKETS_BUFFER_MIN_SIZE", 1); + ADD_INT_CONST(m, "SO_VM_SOCKETS_BUFFER_MAX_SIZE", 2); + ADD_INT_CONST(m, "VMADDR_CID_ANY", 0xffffffff); + ADD_INT_CONST(m, "VMADDR_PORT_ANY", 0xffffffff); + ADD_INT_CONST(m, "VMADDR_CID_HOST", 2); + ADD_INT_CONST(m, "VM_SOCKETS_INVALID_VERSION", 0xffffffff); + ADD_INT_CONST(m, "IOCTL_VM_SOCKETS_GET_LOCAL_CID", _IO(7, 0xb9)); #endif #ifdef AF_ROUTE /* Alias to emulate 4.4BSD */ - PyModule_AddIntMacro(m, AF_ROUTE); + ADD_INT_MACRO(m, AF_ROUTE); #endif #ifdef AF_LINK - PyModule_AddIntMacro(m, AF_LINK); + ADD_INT_MACRO(m, AF_LINK); #endif #ifdef AF_ASH /* Ash */ - PyModule_AddIntMacro(m, AF_ASH); + ADD_INT_MACRO(m, AF_ASH); #endif #ifdef AF_ECONET /* Acorn Econet */ - PyModule_AddIntMacro(m, AF_ECONET); + ADD_INT_MACRO(m, AF_ECONET); #endif #ifdef AF_ATMSVC /* ATM SVCs */ - PyModule_AddIntMacro(m, AF_ATMSVC); + ADD_INT_MACRO(m, AF_ATMSVC); #endif #ifdef AF_SNA /* Linux SNA Project (nutters!) */ - PyModule_AddIntMacro(m, AF_SNA); + ADD_INT_MACRO(m, AF_SNA); #endif #ifdef AF_IRDA /* IRDA sockets */ - PyModule_AddIntMacro(m, AF_IRDA); + ADD_INT_MACRO(m, AF_IRDA); #endif #ifdef AF_PPPOX /* PPPoX sockets */ - PyModule_AddIntMacro(m, AF_PPPOX); + ADD_INT_MACRO(m, AF_PPPOX); #endif #ifdef AF_WANPIPE /* Wanpipe API Sockets */ - PyModule_AddIntMacro(m, AF_WANPIPE); + ADD_INT_MACRO(m, AF_WANPIPE); #endif #ifdef AF_LLC /* Linux LLC */ - PyModule_AddIntMacro(m, AF_LLC); + ADD_INT_MACRO(m, AF_LLC); #endif #ifdef HAVE_AF_HYPERV /* Hyper-V sockets */ - PyModule_AddIntMacro(m, AF_HYPERV); + ADD_INT_MACRO(m, AF_HYPERV); /* for proto */ - PyModule_AddIntMacro(m, HV_PROTOCOL_RAW); + ADD_INT_MACRO(m, HV_PROTOCOL_RAW); /* for setsockopt() */ - PyModule_AddIntMacro(m, HVSOCKET_CONNECT_TIMEOUT); - PyModule_AddIntMacro(m, HVSOCKET_CONNECT_TIMEOUT_MAX); - PyModule_AddIntMacro(m, HVSOCKET_CONNECTED_SUSPEND); - PyModule_AddIntMacro(m, HVSOCKET_ADDRESS_FLAG_PASSTHRU); + ADD_INT_MACRO(m, HVSOCKET_CONNECT_TIMEOUT); + ADD_INT_MACRO(m, HVSOCKET_CONNECT_TIMEOUT_MAX); + ADD_INT_MACRO(m, HVSOCKET_CONNECTED_SUSPEND); + ADD_INT_MACRO(m, HVSOCKET_ADDRESS_FLAG_PASSTHRU); /* for bind() or connect() */ - PyModule_AddStringConstant(m, "HV_GUID_ZERO", "00000000-0000-0000-0000-000000000000"); - PyModule_AddStringConstant(m, "HV_GUID_WILDCARD", "00000000-0000-0000-0000-000000000000"); - PyModule_AddStringConstant(m, "HV_GUID_BROADCAST", "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"); - PyModule_AddStringConstant(m, "HV_GUID_CHILDREN", "90DB8B89-0D35-4F79-8CE9-49EA0AC8B7CD"); - PyModule_AddStringConstant(m, "HV_GUID_LOOPBACK", "E0E16197-DD56-4A10-9195-5EE7A155A838"); - PyModule_AddStringConstant(m, "HV_GUID_PARENT", "A42E7CDA-D03F-480C-9CC2-A4DE20ABB878"); + ADD_STR_CONST(m, "HV_GUID_ZERO", "00000000-0000-0000-0000-000000000000"); + ADD_STR_CONST(m, "HV_GUID_WILDCARD", "00000000-0000-0000-0000-000000000000"); + ADD_STR_CONST(m, "HV_GUID_BROADCAST", "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"); + ADD_STR_CONST(m, "HV_GUID_CHILDREN", "90DB8B89-0D35-4F79-8CE9-49EA0AC8B7CD"); + ADD_STR_CONST(m, "HV_GUID_LOOPBACK", "E0E16197-DD56-4A10-9195-5EE7A155A838"); + ADD_STR_CONST(m, "HV_GUID_PARENT", "A42E7CDA-D03F-480C-9CC2-A4DE20ABB878"); #endif /* HAVE_AF_HYPERV */ #ifdef USE_BLUETOOTH - PyModule_AddIntMacro(m, AF_BLUETOOTH); + ADD_INT_MACRO(m, AF_BLUETOOTH); #ifdef BTPROTO_L2CAP - PyModule_AddIntMacro(m, BTPROTO_L2CAP); + ADD_INT_MACRO(m, BTPROTO_L2CAP); #endif /* BTPROTO_L2CAP */ #ifdef BTPROTO_HCI - PyModule_AddIntMacro(m, BTPROTO_HCI); - PyModule_AddIntMacro(m, SOL_HCI); + ADD_INT_MACRO(m, BTPROTO_HCI); + ADD_INT_MACRO(m, SOL_HCI); #if !defined(__NetBSD__) && !defined(__DragonFly__) - PyModule_AddIntMacro(m, HCI_FILTER); + ADD_INT_MACRO(m, HCI_FILTER); #if !defined(__FreeBSD__) - PyModule_AddIntMacro(m, HCI_TIME_STAMP); - PyModule_AddIntMacro(m, HCI_DATA_DIR); + ADD_INT_MACRO(m, HCI_TIME_STAMP); + ADD_INT_MACRO(m, HCI_DATA_DIR); #endif /* !__FreeBSD__ */ #endif /* !__NetBSD__ && !__DragonFly__ */ #endif /* BTPROTO_HCI */ #ifdef BTPROTO_RFCOMM - PyModule_AddIntMacro(m, BTPROTO_RFCOMM); + ADD_INT_MACRO(m, BTPROTO_RFCOMM); #endif /* BTPROTO_RFCOMM */ - PyModule_AddStringConstant(m, "BDADDR_ANY", "00:00:00:00:00:00"); - PyModule_AddStringConstant(m, "BDADDR_LOCAL", "00:00:00:FF:FF:FF"); + ADD_STR_CONST(m, "BDADDR_ANY", "00:00:00:00:00:00"); + ADD_STR_CONST(m, "BDADDR_LOCAL", "00:00:00:FF:FF:FF"); #ifdef BTPROTO_SCO - PyModule_AddIntMacro(m, BTPROTO_SCO); + ADD_INT_MACRO(m, BTPROTO_SCO); #endif /* BTPROTO_SCO */ #endif /* USE_BLUETOOTH */ #ifdef AF_CAN /* Controller Area Network */ - PyModule_AddIntMacro(m, AF_CAN); + ADD_INT_MACRO(m, AF_CAN); #endif #ifdef PF_CAN /* Controller Area Network */ - PyModule_AddIntMacro(m, PF_CAN); + ADD_INT_MACRO(m, PF_CAN); #endif /* Reliable Datagram Sockets */ #ifdef AF_RDS - PyModule_AddIntMacro(m, AF_RDS); + ADD_INT_MACRO(m, AF_RDS); #endif #ifdef PF_RDS - PyModule_AddIntMacro(m, PF_RDS); + ADD_INT_MACRO(m, PF_RDS); #endif /* Kernel event messages */ #ifdef PF_SYSTEM - PyModule_AddIntMacro(m, PF_SYSTEM); + ADD_INT_MACRO(m, PF_SYSTEM); #endif #ifdef AF_SYSTEM - PyModule_AddIntMacro(m, AF_SYSTEM); + ADD_INT_MACRO(m, AF_SYSTEM); #endif #ifdef AF_PACKET - PyModule_AddIntMacro(m, AF_PACKET); + ADD_INT_MACRO(m, AF_PACKET); #endif #ifdef PF_PACKET - PyModule_AddIntMacro(m, PF_PACKET); + ADD_INT_MACRO(m, PF_PACKET); #endif #ifdef PACKET_HOST - PyModule_AddIntMacro(m, PACKET_HOST); + ADD_INT_MACRO(m, PACKET_HOST); #endif #ifdef PACKET_BROADCAST - PyModule_AddIntMacro(m, PACKET_BROADCAST); + ADD_INT_MACRO(m, PACKET_BROADCAST); #endif #ifdef PACKET_MULTICAST - PyModule_AddIntMacro(m, PACKET_MULTICAST); + ADD_INT_MACRO(m, PACKET_MULTICAST); #endif #ifdef PACKET_OTHERHOST - PyModule_AddIntMacro(m, PACKET_OTHERHOST); + ADD_INT_MACRO(m, PACKET_OTHERHOST); #endif #ifdef PACKET_OUTGOING - PyModule_AddIntMacro(m, PACKET_OUTGOING); + ADD_INT_MACRO(m, PACKET_OUTGOING); #endif #ifdef PACKET_LOOPBACK - PyModule_AddIntMacro(m, PACKET_LOOPBACK); + ADD_INT_MACRO(m, PACKET_LOOPBACK); #endif #ifdef PACKET_FASTROUTE - PyModule_AddIntMacro(m, PACKET_FASTROUTE); + ADD_INT_MACRO(m, PACKET_FASTROUTE); #endif #ifdef HAVE_LINUX_TIPC_H - PyModule_AddIntMacro(m, AF_TIPC); + ADD_INT_MACRO(m, AF_TIPC); /* for addresses */ - PyModule_AddIntMacro(m, TIPC_ADDR_NAMESEQ); - PyModule_AddIntMacro(m, TIPC_ADDR_NAME); - PyModule_AddIntMacro(m, TIPC_ADDR_ID); + ADD_INT_MACRO(m, TIPC_ADDR_NAMESEQ); + ADD_INT_MACRO(m, TIPC_ADDR_NAME); + ADD_INT_MACRO(m, TIPC_ADDR_ID); - PyModule_AddIntMacro(m, TIPC_ZONE_SCOPE); - PyModule_AddIntMacro(m, TIPC_CLUSTER_SCOPE); - PyModule_AddIntMacro(m, TIPC_NODE_SCOPE); + ADD_INT_MACRO(m, TIPC_ZONE_SCOPE); + ADD_INT_MACRO(m, TIPC_CLUSTER_SCOPE); + ADD_INT_MACRO(m, TIPC_NODE_SCOPE); /* for setsockopt() */ - PyModule_AddIntMacro(m, SOL_TIPC); - PyModule_AddIntMacro(m, TIPC_IMPORTANCE); - PyModule_AddIntMacro(m, TIPC_SRC_DROPPABLE); - PyModule_AddIntMacro(m, TIPC_DEST_DROPPABLE); - PyModule_AddIntMacro(m, TIPC_CONN_TIMEOUT); + ADD_INT_MACRO(m, SOL_TIPC); + ADD_INT_MACRO(m, TIPC_IMPORTANCE); + ADD_INT_MACRO(m, TIPC_SRC_DROPPABLE); + ADD_INT_MACRO(m, TIPC_DEST_DROPPABLE); + ADD_INT_MACRO(m, TIPC_CONN_TIMEOUT); - PyModule_AddIntMacro(m, TIPC_LOW_IMPORTANCE); - PyModule_AddIntMacro(m, TIPC_MEDIUM_IMPORTANCE); - PyModule_AddIntMacro(m, TIPC_HIGH_IMPORTANCE); - PyModule_AddIntMacro(m, TIPC_CRITICAL_IMPORTANCE); + ADD_INT_MACRO(m, TIPC_LOW_IMPORTANCE); + ADD_INT_MACRO(m, TIPC_MEDIUM_IMPORTANCE); + ADD_INT_MACRO(m, TIPC_HIGH_IMPORTANCE); + ADD_INT_MACRO(m, TIPC_CRITICAL_IMPORTANCE); /* for subscriptions */ - PyModule_AddIntMacro(m, TIPC_SUB_PORTS); - PyModule_AddIntMacro(m, TIPC_SUB_SERVICE); + ADD_INT_MACRO(m, TIPC_SUB_PORTS); + ADD_INT_MACRO(m, TIPC_SUB_SERVICE); #ifdef TIPC_SUB_CANCEL /* doesn't seem to be available everywhere */ - PyModule_AddIntMacro(m, TIPC_SUB_CANCEL); + ADD_INT_MACRO(m, TIPC_SUB_CANCEL); #endif - PyModule_AddIntMacro(m, TIPC_WAIT_FOREVER); - PyModule_AddIntMacro(m, TIPC_PUBLISHED); - PyModule_AddIntMacro(m, TIPC_WITHDRAWN); - PyModule_AddIntMacro(m, TIPC_SUBSCR_TIMEOUT); - PyModule_AddIntMacro(m, TIPC_CFG_SRV); - PyModule_AddIntMacro(m, TIPC_TOP_SRV); + ADD_INT_MACRO(m, TIPC_WAIT_FOREVER); + ADD_INT_MACRO(m, TIPC_PUBLISHED); + ADD_INT_MACRO(m, TIPC_WITHDRAWN); + ADD_INT_MACRO(m, TIPC_SUBSCR_TIMEOUT); + ADD_INT_MACRO(m, TIPC_CFG_SRV); + ADD_INT_MACRO(m, TIPC_TOP_SRV); #endif #ifdef HAVE_SOCKADDR_ALG /* Socket options */ - PyModule_AddIntMacro(m, ALG_SET_KEY); - PyModule_AddIntMacro(m, ALG_SET_IV); - PyModule_AddIntMacro(m, ALG_SET_OP); - PyModule_AddIntMacro(m, ALG_SET_AEAD_ASSOCLEN); - PyModule_AddIntMacro(m, ALG_SET_AEAD_AUTHSIZE); - PyModule_AddIntMacro(m, ALG_SET_PUBKEY); + ADD_INT_MACRO(m, ALG_SET_KEY); + ADD_INT_MACRO(m, ALG_SET_IV); + ADD_INT_MACRO(m, ALG_SET_OP); + ADD_INT_MACRO(m, ALG_SET_AEAD_ASSOCLEN); + ADD_INT_MACRO(m, ALG_SET_AEAD_AUTHSIZE); + ADD_INT_MACRO(m, ALG_SET_PUBKEY); /* Operations */ - PyModule_AddIntMacro(m, ALG_OP_DECRYPT); - PyModule_AddIntMacro(m, ALG_OP_ENCRYPT); - PyModule_AddIntMacro(m, ALG_OP_SIGN); - PyModule_AddIntMacro(m, ALG_OP_VERIFY); + ADD_INT_MACRO(m, ALG_OP_DECRYPT); + ADD_INT_MACRO(m, ALG_OP_ENCRYPT); + ADD_INT_MACRO(m, ALG_OP_SIGN); + ADD_INT_MACRO(m, ALG_OP_VERIFY); #endif /* IEEE 802.3 protocol numbers required for a standard TCP/IP network stack */ #ifdef ETHERTYPE_ARP - PyModule_AddIntMacro(m, ETHERTYPE_ARP); + ADD_INT_MACRO(m, ETHERTYPE_ARP); #endif #ifdef ETHERTYPE_IP - PyModule_AddIntMacro(m, ETHERTYPE_IP); + ADD_INT_MACRO(m, ETHERTYPE_IP); #endif #ifdef ETHERTYPE_IPV6 - PyModule_AddIntMacro(m, ETHERTYPE_IPV6); + ADD_INT_MACRO(m, ETHERTYPE_IPV6); #endif #ifdef ETHERTYPE_VLAN - PyModule_AddIntMacro(m, ETHERTYPE_VLAN); + ADD_INT_MACRO(m, ETHERTYPE_VLAN); #endif /* Linux pseudo-protocol for sniffing every packet */ #ifdef ETH_P_ALL - PyModule_AddIntMacro(m, ETH_P_ALL); + ADD_INT_MACRO(m, ETH_P_ALL); #endif /* Socket types */ - PyModule_AddIntMacro(m, SOCK_STREAM); - PyModule_AddIntMacro(m, SOCK_DGRAM); + ADD_INT_MACRO(m, SOCK_STREAM); + ADD_INT_MACRO(m, SOCK_DGRAM); /* We have incomplete socket support. */ #ifdef SOCK_RAW /* SOCK_RAW is marked as optional in the POSIX specification */ - PyModule_AddIntMacro(m, SOCK_RAW); + ADD_INT_MACRO(m, SOCK_RAW); #endif #ifdef SOCK_SEQPACKET - PyModule_AddIntMacro(m, SOCK_SEQPACKET); + ADD_INT_MACRO(m, SOCK_SEQPACKET); #endif #if defined(SOCK_RDM) - PyModule_AddIntMacro(m, SOCK_RDM); + ADD_INT_MACRO(m, SOCK_RDM); #endif #ifdef SOCK_CLOEXEC - PyModule_AddIntMacro(m, SOCK_CLOEXEC); + ADD_INT_MACRO(m, SOCK_CLOEXEC); #endif #ifdef SOCK_NONBLOCK - PyModule_AddIntMacro(m, SOCK_NONBLOCK); + ADD_INT_MACRO(m, SOCK_NONBLOCK); #endif #ifdef SO_DEBUG - PyModule_AddIntMacro(m, SO_DEBUG); + ADD_INT_MACRO(m, SO_DEBUG); #endif #ifdef SO_ACCEPTCONN - PyModule_AddIntMacro(m, SO_ACCEPTCONN); + ADD_INT_MACRO(m, SO_ACCEPTCONN); #endif #ifdef SO_REUSEADDR - PyModule_AddIntMacro(m, SO_REUSEADDR); + ADD_INT_MACRO(m, SO_REUSEADDR); #endif #ifdef SO_EXCLUSIVEADDRUSE - PyModule_AddIntMacro(m, SO_EXCLUSIVEADDRUSE); + ADD_INT_MACRO(m, SO_EXCLUSIVEADDRUSE); #endif #ifdef SO_INCOMING_CPU - PyModule_AddIntMacro(m, SO_INCOMING_CPU); + ADD_INT_MACRO(m, SO_INCOMING_CPU); #endif #ifdef SO_KEEPALIVE - PyModule_AddIntMacro(m, SO_KEEPALIVE); + ADD_INT_MACRO(m, SO_KEEPALIVE); #endif #ifdef SO_DONTROUTE - PyModule_AddIntMacro(m, SO_DONTROUTE); + ADD_INT_MACRO(m, SO_DONTROUTE); #endif #ifdef SO_BROADCAST - PyModule_AddIntMacro(m, SO_BROADCAST); + ADD_INT_MACRO(m, SO_BROADCAST); #endif #ifdef SO_USELOOPBACK - PyModule_AddIntMacro(m, SO_USELOOPBACK); + ADD_INT_MACRO(m, SO_USELOOPBACK); #endif #ifdef SO_LINGER - PyModule_AddIntMacro(m, SO_LINGER); + ADD_INT_MACRO(m, SO_LINGER); #endif #ifdef SO_OOBINLINE - PyModule_AddIntMacro(m, SO_OOBINLINE); + ADD_INT_MACRO(m, SO_OOBINLINE); #endif #ifndef __GNU__ #ifdef SO_REUSEPORT - PyModule_AddIntMacro(m, SO_REUSEPORT); + ADD_INT_MACRO(m, SO_REUSEPORT); #endif #endif #ifdef SO_SNDBUF - PyModule_AddIntMacro(m, SO_SNDBUF); + ADD_INT_MACRO(m, SO_SNDBUF); #endif #ifdef SO_RCVBUF - PyModule_AddIntMacro(m, SO_RCVBUF); + ADD_INT_MACRO(m, SO_RCVBUF); #endif #ifdef SO_SNDLOWAT - PyModule_AddIntMacro(m, SO_SNDLOWAT); + ADD_INT_MACRO(m, SO_SNDLOWAT); #endif #ifdef SO_RCVLOWAT - PyModule_AddIntMacro(m, SO_RCVLOWAT); + ADD_INT_MACRO(m, SO_RCVLOWAT); #endif #ifdef SO_SNDTIMEO - PyModule_AddIntMacro(m, SO_SNDTIMEO); + ADD_INT_MACRO(m, SO_SNDTIMEO); #endif #ifdef SO_RCVTIMEO - PyModule_AddIntMacro(m, SO_RCVTIMEO); + ADD_INT_MACRO(m, SO_RCVTIMEO); #endif #ifdef SO_ERROR - PyModule_AddIntMacro(m, SO_ERROR); + ADD_INT_MACRO(m, SO_ERROR); #endif #ifdef SO_TYPE - PyModule_AddIntMacro(m, SO_TYPE); + ADD_INT_MACRO(m, SO_TYPE); #endif #ifdef SO_SETFIB - PyModule_AddIntMacro(m, SO_SETFIB); + ADD_INT_MACRO(m, SO_SETFIB); #endif #ifdef SO_PASSCRED - PyModule_AddIntMacro(m, SO_PASSCRED); + ADD_INT_MACRO(m, SO_PASSCRED); #endif #ifdef SO_PEERCRED - PyModule_AddIntMacro(m, SO_PEERCRED); + ADD_INT_MACRO(m, SO_PEERCRED); #endif #ifdef LOCAL_PEERCRED - PyModule_AddIntMacro(m, LOCAL_PEERCRED); + ADD_INT_MACRO(m, LOCAL_PEERCRED); #endif #ifdef SO_PASSSEC - PyModule_AddIntMacro(m, SO_PASSSEC); + ADD_INT_MACRO(m, SO_PASSSEC); #endif #ifdef SO_PEERSEC - PyModule_AddIntMacro(m, SO_PEERSEC); + ADD_INT_MACRO(m, SO_PEERSEC); #endif #ifdef SO_BINDTODEVICE - PyModule_AddIntMacro(m, SO_BINDTODEVICE); + ADD_INT_MACRO(m, SO_BINDTODEVICE); #endif #ifdef SO_PRIORITY - PyModule_AddIntMacro(m, SO_PRIORITY); + ADD_INT_MACRO(m, SO_PRIORITY); #endif #ifdef SO_MARK - PyModule_AddIntMacro(m, SO_MARK); + ADD_INT_MACRO(m, SO_MARK); #endif #ifdef SO_USER_COOKIE - PyModule_AddIntMacro(m, SO_USER_COOKIE); + ADD_INT_MACRO(m, SO_USER_COOKIE); #endif #ifdef SO_RTABLE - PyModule_AddIntMacro(m, SO_RTABLE); + ADD_INT_MACRO(m, SO_RTABLE); #endif #ifdef SO_DOMAIN - PyModule_AddIntMacro(m, SO_DOMAIN); + ADD_INT_MACRO(m, SO_DOMAIN); #endif #ifdef SO_PROTOCOL - PyModule_AddIntMacro(m, SO_PROTOCOL); + ADD_INT_MACRO(m, SO_PROTOCOL); #endif #ifdef LOCAL_CREDS - PyModule_AddIntMacro(m, LOCAL_CREDS); + ADD_INT_MACRO(m, LOCAL_CREDS); #endif #ifdef LOCAL_CREDS_PERSISTENT - PyModule_AddIntMacro(m, LOCAL_CREDS_PERSISTENT); + ADD_INT_MACRO(m, LOCAL_CREDS_PERSISTENT); #endif /* Maximum number of connections for "listen" */ #ifdef SOMAXCONN - PyModule_AddIntMacro(m, SOMAXCONN); + ADD_INT_MACRO(m, SOMAXCONN); #else - PyModule_AddIntConstant(m, "SOMAXCONN", 5); /* Common value */ + ADD_INT_CONST(m, "SOMAXCONN", 5); /* Common value */ #endif /* Ancillary message types */ #ifdef SCM_RIGHTS - PyModule_AddIntMacro(m, SCM_RIGHTS); + ADD_INT_MACRO(m, SCM_RIGHTS); #endif #ifdef SCM_CREDENTIALS - PyModule_AddIntMacro(m, SCM_CREDENTIALS); + ADD_INT_MACRO(m, SCM_CREDENTIALS); #endif #ifdef SCM_CREDS - PyModule_AddIntMacro(m, SCM_CREDS); + ADD_INT_MACRO(m, SCM_CREDS); #endif #ifdef SCM_CREDS2 - PyModule_AddIntMacro(m, SCM_CREDS2); + ADD_INT_MACRO(m, SCM_CREDS2); #endif /* Flags for send, recv */ #ifdef MSG_OOB - PyModule_AddIntMacro(m, MSG_OOB); + ADD_INT_MACRO(m, MSG_OOB); #endif #ifdef MSG_PEEK - PyModule_AddIntMacro(m, MSG_PEEK); + ADD_INT_MACRO(m, MSG_PEEK); #endif #ifdef MSG_DONTROUTE - PyModule_AddIntMacro(m, MSG_DONTROUTE); + ADD_INT_MACRO(m, MSG_DONTROUTE); #endif #ifdef MSG_DONTWAIT - PyModule_AddIntMacro(m, MSG_DONTWAIT); + ADD_INT_MACRO(m, MSG_DONTWAIT); #endif #ifdef MSG_EOR - PyModule_AddIntMacro(m, MSG_EOR); + ADD_INT_MACRO(m, MSG_EOR); #endif #ifdef MSG_TRUNC // workaround for https://github.com/WebAssembly/wasi-libc/issues/305 #if defined(__wasi__) && !defined(__WASI_RIFLAGS_RECV_DATA_TRUNCATED) # define __WASI_RIFLAGS_RECV_DATA_TRUNCATED 2 #endif - PyModule_AddIntMacro(m, MSG_TRUNC); + ADD_INT_MACRO(m, MSG_TRUNC); #endif #ifdef MSG_CTRUNC - PyModule_AddIntMacro(m, MSG_CTRUNC); + ADD_INT_MACRO(m, MSG_CTRUNC); #endif #ifdef MSG_WAITALL - PyModule_AddIntMacro(m, MSG_WAITALL); + ADD_INT_MACRO(m, MSG_WAITALL); #endif #ifdef MSG_BTAG - PyModule_AddIntMacro(m, MSG_BTAG); + ADD_INT_MACRO(m, MSG_BTAG); #endif #ifdef MSG_ETAG - PyModule_AddIntMacro(m, MSG_ETAG); + ADD_INT_MACRO(m, MSG_ETAG); #endif #ifdef MSG_NOSIGNAL - PyModule_AddIntMacro(m, MSG_NOSIGNAL); + ADD_INT_MACRO(m, MSG_NOSIGNAL); #endif #ifdef MSG_NOTIFICATION - PyModule_AddIntMacro(m, MSG_NOTIFICATION); + ADD_INT_MACRO(m, MSG_NOTIFICATION); #endif #ifdef MSG_CMSG_CLOEXEC - PyModule_AddIntMacro(m, MSG_CMSG_CLOEXEC); + ADD_INT_MACRO(m, MSG_CMSG_CLOEXEC); #endif #ifdef MSG_ERRQUEUE - PyModule_AddIntMacro(m, MSG_ERRQUEUE); + ADD_INT_MACRO(m, MSG_ERRQUEUE); #endif #ifdef MSG_CONFIRM - PyModule_AddIntMacro(m, MSG_CONFIRM); + ADD_INT_MACRO(m, MSG_CONFIRM); #endif #ifdef MSG_MORE - PyModule_AddIntMacro(m, MSG_MORE); + ADD_INT_MACRO(m, MSG_MORE); #endif #ifdef MSG_EOF - PyModule_AddIntMacro(m, MSG_EOF); + ADD_INT_MACRO(m, MSG_EOF); #endif #ifdef MSG_BCAST - PyModule_AddIntMacro(m, MSG_BCAST); + ADD_INT_MACRO(m, MSG_BCAST); #endif #ifdef MSG_MCAST - PyModule_AddIntMacro(m, MSG_MCAST); + ADD_INT_MACRO(m, MSG_MCAST); #endif #ifdef MSG_FASTOPEN - PyModule_AddIntMacro(m, MSG_FASTOPEN); + ADD_INT_MACRO(m, MSG_FASTOPEN); #endif /* Protocol level and numbers, usable for [gs]etsockopt */ #ifdef SOL_SOCKET - PyModule_AddIntMacro(m, SOL_SOCKET); + ADD_INT_MACRO(m, SOL_SOCKET); #endif #ifdef SOL_IP - PyModule_AddIntMacro(m, SOL_IP); + ADD_INT_MACRO(m, SOL_IP); #else - PyModule_AddIntConstant(m, "SOL_IP", 0); + ADD_INT_CONST(m, "SOL_IP", 0); #endif #ifdef SOL_IPX - PyModule_AddIntMacro(m, SOL_IPX); + ADD_INT_MACRO(m, SOL_IPX); #endif #ifdef SOL_AX25 - PyModule_AddIntMacro(m, SOL_AX25); + ADD_INT_MACRO(m, SOL_AX25); #endif #ifdef SOL_ATALK - PyModule_AddIntMacro(m, SOL_ATALK); + ADD_INT_MACRO(m, SOL_ATALK); #endif #ifdef SOL_NETROM - PyModule_AddIntMacro(m, SOL_NETROM); + ADD_INT_MACRO(m, SOL_NETROM); #endif #ifdef SOL_ROSE - PyModule_AddIntMacro(m, SOL_ROSE); + ADD_INT_MACRO(m, SOL_ROSE); #endif #ifdef SOL_TCP - PyModule_AddIntMacro(m, SOL_TCP); + ADD_INT_MACRO(m, SOL_TCP); #else - PyModule_AddIntConstant(m, "SOL_TCP", 6); + ADD_INT_CONST(m, "SOL_TCP", 6); #endif #ifdef SOL_UDP - PyModule_AddIntMacro(m, SOL_UDP); + ADD_INT_MACRO(m, SOL_UDP); #else - PyModule_AddIntConstant(m, "SOL_UDP", 17); + ADD_INT_CONST(m, "SOL_UDP", 17); #endif #ifdef SOL_CAN_BASE - PyModule_AddIntMacro(m, SOL_CAN_BASE); + ADD_INT_MACRO(m, SOL_CAN_BASE); #endif #ifdef SOL_CAN_RAW - PyModule_AddIntMacro(m, SOL_CAN_RAW); - PyModule_AddIntMacro(m, CAN_RAW); + ADD_INT_MACRO(m, SOL_CAN_RAW); + ADD_INT_MACRO(m, CAN_RAW); #endif #if defined(HAVE_LINUX_CAN_H) || defined(HAVE_NETCAN_CAN_H) - PyModule_AddIntMacro(m, CAN_EFF_FLAG); - PyModule_AddIntMacro(m, CAN_RTR_FLAG); - PyModule_AddIntMacro(m, CAN_ERR_FLAG); + ADD_INT_MACRO(m, CAN_EFF_FLAG); + ADD_INT_MACRO(m, CAN_RTR_FLAG); + ADD_INT_MACRO(m, CAN_ERR_FLAG); - PyModule_AddIntMacro(m, CAN_SFF_MASK); - PyModule_AddIntMacro(m, CAN_EFF_MASK); - PyModule_AddIntMacro(m, CAN_ERR_MASK); + ADD_INT_MACRO(m, CAN_SFF_MASK); + ADD_INT_MACRO(m, CAN_EFF_MASK); + ADD_INT_MACRO(m, CAN_ERR_MASK); #ifdef CAN_ISOTP - PyModule_AddIntMacro(m, CAN_ISOTP); + ADD_INT_MACRO(m, CAN_ISOTP); #endif #ifdef CAN_J1939 - PyModule_AddIntMacro(m, CAN_J1939); + ADD_INT_MACRO(m, CAN_J1939); #endif #endif #if defined(HAVE_LINUX_CAN_RAW_H) || defined(HAVE_NETCAN_CAN_H) - PyModule_AddIntMacro(m, CAN_RAW_FILTER); + ADD_INT_MACRO(m, CAN_RAW_FILTER); #ifdef CAN_RAW_ERR_FILTER - PyModule_AddIntMacro(m, CAN_RAW_ERR_FILTER); + ADD_INT_MACRO(m, CAN_RAW_ERR_FILTER); #endif - PyModule_AddIntMacro(m, CAN_RAW_LOOPBACK); - PyModule_AddIntMacro(m, CAN_RAW_RECV_OWN_MSGS); + ADD_INT_MACRO(m, CAN_RAW_LOOPBACK); + ADD_INT_MACRO(m, CAN_RAW_RECV_OWN_MSGS); #endif #ifdef HAVE_LINUX_CAN_RAW_FD_FRAMES - PyModule_AddIntMacro(m, CAN_RAW_FD_FRAMES); + ADD_INT_MACRO(m, CAN_RAW_FD_FRAMES); #endif #ifdef HAVE_LINUX_CAN_RAW_JOIN_FILTERS - PyModule_AddIntMacro(m, CAN_RAW_JOIN_FILTERS); + ADD_INT_MACRO(m, CAN_RAW_JOIN_FILTERS); #endif #ifdef HAVE_LINUX_CAN_BCM_H - PyModule_AddIntMacro(m, CAN_BCM); + ADD_INT_MACRO(m, CAN_BCM); /* BCM opcodes */ - PyModule_AddIntConstant(m, "CAN_BCM_TX_SETUP", TX_SETUP); - PyModule_AddIntConstant(m, "CAN_BCM_TX_DELETE", TX_DELETE); - PyModule_AddIntConstant(m, "CAN_BCM_TX_READ", TX_READ); - PyModule_AddIntConstant(m, "CAN_BCM_TX_SEND", TX_SEND); - PyModule_AddIntConstant(m, "CAN_BCM_RX_SETUP", RX_SETUP); - PyModule_AddIntConstant(m, "CAN_BCM_RX_DELETE", RX_DELETE); - PyModule_AddIntConstant(m, "CAN_BCM_RX_READ", RX_READ); - PyModule_AddIntConstant(m, "CAN_BCM_TX_STATUS", TX_STATUS); - PyModule_AddIntConstant(m, "CAN_BCM_TX_EXPIRED", TX_EXPIRED); - PyModule_AddIntConstant(m, "CAN_BCM_RX_STATUS", RX_STATUS); - PyModule_AddIntConstant(m, "CAN_BCM_RX_TIMEOUT", RX_TIMEOUT); - PyModule_AddIntConstant(m, "CAN_BCM_RX_CHANGED", RX_CHANGED); + ADD_INT_CONST(m, "CAN_BCM_TX_SETUP", TX_SETUP); + ADD_INT_CONST(m, "CAN_BCM_TX_DELETE", TX_DELETE); + ADD_INT_CONST(m, "CAN_BCM_TX_READ", TX_READ); + ADD_INT_CONST(m, "CAN_BCM_TX_SEND", TX_SEND); + ADD_INT_CONST(m, "CAN_BCM_RX_SETUP", RX_SETUP); + ADD_INT_CONST(m, "CAN_BCM_RX_DELETE", RX_DELETE); + ADD_INT_CONST(m, "CAN_BCM_RX_READ", RX_READ); + ADD_INT_CONST(m, "CAN_BCM_TX_STATUS", TX_STATUS); + ADD_INT_CONST(m, "CAN_BCM_TX_EXPIRED", TX_EXPIRED); + ADD_INT_CONST(m, "CAN_BCM_RX_STATUS", RX_STATUS); + ADD_INT_CONST(m, "CAN_BCM_RX_TIMEOUT", RX_TIMEOUT); + ADD_INT_CONST(m, "CAN_BCM_RX_CHANGED", RX_CHANGED); /* BCM flags */ - PyModule_AddIntConstant(m, "CAN_BCM_SETTIMER", SETTIMER); - PyModule_AddIntConstant(m, "CAN_BCM_STARTTIMER", STARTTIMER); - PyModule_AddIntConstant(m, "CAN_BCM_TX_COUNTEVT", TX_COUNTEVT); - PyModule_AddIntConstant(m, "CAN_BCM_TX_ANNOUNCE", TX_ANNOUNCE); - PyModule_AddIntConstant(m, "CAN_BCM_TX_CP_CAN_ID", TX_CP_CAN_ID); - PyModule_AddIntConstant(m, "CAN_BCM_RX_FILTER_ID", RX_FILTER_ID); - PyModule_AddIntConstant(m, "CAN_BCM_RX_CHECK_DLC", RX_CHECK_DLC); - PyModule_AddIntConstant(m, "CAN_BCM_RX_NO_AUTOTIMER", RX_NO_AUTOTIMER); - PyModule_AddIntConstant(m, "CAN_BCM_RX_ANNOUNCE_RESUME", RX_ANNOUNCE_RESUME); - PyModule_AddIntConstant(m, "CAN_BCM_TX_RESET_MULTI_IDX", TX_RESET_MULTI_IDX); - PyModule_AddIntConstant(m, "CAN_BCM_RX_RTR_FRAME", RX_RTR_FRAME); + ADD_INT_CONST(m, "CAN_BCM_SETTIMER", SETTIMER); + ADD_INT_CONST(m, "CAN_BCM_STARTTIMER", STARTTIMER); + ADD_INT_CONST(m, "CAN_BCM_TX_COUNTEVT", TX_COUNTEVT); + ADD_INT_CONST(m, "CAN_BCM_TX_ANNOUNCE", TX_ANNOUNCE); + ADD_INT_CONST(m, "CAN_BCM_TX_CP_CAN_ID", TX_CP_CAN_ID); + ADD_INT_CONST(m, "CAN_BCM_RX_FILTER_ID", RX_FILTER_ID); + ADD_INT_CONST(m, "CAN_BCM_RX_CHECK_DLC", RX_CHECK_DLC); + ADD_INT_CONST(m, "CAN_BCM_RX_NO_AUTOTIMER", RX_NO_AUTOTIMER); + ADD_INT_CONST(m, "CAN_BCM_RX_ANNOUNCE_RESUME", RX_ANNOUNCE_RESUME); + ADD_INT_CONST(m, "CAN_BCM_TX_RESET_MULTI_IDX", TX_RESET_MULTI_IDX); + ADD_INT_CONST(m, "CAN_BCM_RX_RTR_FRAME", RX_RTR_FRAME); #ifdef CAN_FD_FRAME /* CAN_FD_FRAME was only introduced in the 4.8.x kernel series */ - PyModule_AddIntConstant(m, "CAN_BCM_CAN_FD_FRAME", CAN_FD_FRAME); + ADD_INT_CONST(m, "CAN_BCM_CAN_FD_FRAME", CAN_FD_FRAME); #endif #endif #ifdef HAVE_LINUX_CAN_J1939_H - PyModule_AddIntMacro(m, J1939_MAX_UNICAST_ADDR); - PyModule_AddIntMacro(m, J1939_IDLE_ADDR); - PyModule_AddIntMacro(m, J1939_NO_ADDR); - PyModule_AddIntMacro(m, J1939_NO_NAME); - PyModule_AddIntMacro(m, J1939_PGN_REQUEST); - PyModule_AddIntMacro(m, J1939_PGN_ADDRESS_CLAIMED); - PyModule_AddIntMacro(m, J1939_PGN_ADDRESS_COMMANDED); - PyModule_AddIntMacro(m, J1939_PGN_PDU1_MAX); - PyModule_AddIntMacro(m, J1939_PGN_MAX); - PyModule_AddIntMacro(m, J1939_NO_PGN); + ADD_INT_MACRO(m, J1939_MAX_UNICAST_ADDR); + ADD_INT_MACRO(m, J1939_IDLE_ADDR); + ADD_INT_MACRO(m, J1939_NO_ADDR); + ADD_INT_MACRO(m, J1939_NO_NAME); + ADD_INT_MACRO(m, J1939_PGN_REQUEST); + ADD_INT_MACRO(m, J1939_PGN_ADDRESS_CLAIMED); + ADD_INT_MACRO(m, J1939_PGN_ADDRESS_COMMANDED); + ADD_INT_MACRO(m, J1939_PGN_PDU1_MAX); + ADD_INT_MACRO(m, J1939_PGN_MAX); + ADD_INT_MACRO(m, J1939_NO_PGN); /* J1939 socket options */ - PyModule_AddIntMacro(m, SO_J1939_FILTER); - PyModule_AddIntMacro(m, SO_J1939_PROMISC); - PyModule_AddIntMacro(m, SO_J1939_SEND_PRIO); - PyModule_AddIntMacro(m, SO_J1939_ERRQUEUE); + ADD_INT_MACRO(m, SO_J1939_FILTER); + ADD_INT_MACRO(m, SO_J1939_PROMISC); + ADD_INT_MACRO(m, SO_J1939_SEND_PRIO); + ADD_INT_MACRO(m, SO_J1939_ERRQUEUE); - PyModule_AddIntMacro(m, SCM_J1939_DEST_ADDR); - PyModule_AddIntMacro(m, SCM_J1939_DEST_NAME); - PyModule_AddIntMacro(m, SCM_J1939_PRIO); - PyModule_AddIntMacro(m, SCM_J1939_ERRQUEUE); + ADD_INT_MACRO(m, SCM_J1939_DEST_ADDR); + ADD_INT_MACRO(m, SCM_J1939_DEST_NAME); + ADD_INT_MACRO(m, SCM_J1939_PRIO); + ADD_INT_MACRO(m, SCM_J1939_ERRQUEUE); - PyModule_AddIntMacro(m, J1939_NLA_PAD); - PyModule_AddIntMacro(m, J1939_NLA_BYTES_ACKED); + ADD_INT_MACRO(m, J1939_NLA_PAD); + ADD_INT_MACRO(m, J1939_NLA_BYTES_ACKED); - PyModule_AddIntMacro(m, J1939_EE_INFO_NONE); - PyModule_AddIntMacro(m, J1939_EE_INFO_TX_ABORT); + ADD_INT_MACRO(m, J1939_EE_INFO_NONE); + ADD_INT_MACRO(m, J1939_EE_INFO_TX_ABORT); - PyModule_AddIntMacro(m, J1939_FILTER_MAX); + ADD_INT_MACRO(m, J1939_FILTER_MAX); #endif #ifdef SOL_RDS - PyModule_AddIntMacro(m, SOL_RDS); + ADD_INT_MACRO(m, SOL_RDS); #endif #ifdef HAVE_SOCKADDR_ALG - PyModule_AddIntMacro(m, SOL_ALG); + ADD_INT_MACRO(m, SOL_ALG); #endif #ifdef RDS_CANCEL_SENT_TO - PyModule_AddIntMacro(m, RDS_CANCEL_SENT_TO); + ADD_INT_MACRO(m, RDS_CANCEL_SENT_TO); #endif #ifdef RDS_GET_MR - PyModule_AddIntMacro(m, RDS_GET_MR); + ADD_INT_MACRO(m, RDS_GET_MR); #endif #ifdef RDS_FREE_MR - PyModule_AddIntMacro(m, RDS_FREE_MR); + ADD_INT_MACRO(m, RDS_FREE_MR); #endif #ifdef RDS_RECVERR - PyModule_AddIntMacro(m, RDS_RECVERR); + ADD_INT_MACRO(m, RDS_RECVERR); #endif #ifdef RDS_CONG_MONITOR - PyModule_AddIntMacro(m, RDS_CONG_MONITOR); + ADD_INT_MACRO(m, RDS_CONG_MONITOR); #endif #ifdef RDS_GET_MR_FOR_DEST - PyModule_AddIntMacro(m, RDS_GET_MR_FOR_DEST); + ADD_INT_MACRO(m, RDS_GET_MR_FOR_DEST); #endif #ifdef IPPROTO_IP - PyModule_AddIntMacro(m, IPPROTO_IP); + ADD_INT_MACRO(m, IPPROTO_IP); #else - PyModule_AddIntConstant(m, "IPPROTO_IP", 0); + ADD_INT_CONST(m, "IPPROTO_IP", 0); #endif #ifdef IPPROTO_HOPOPTS - PyModule_AddIntMacro(m, IPPROTO_HOPOPTS); + ADD_INT_MACRO(m, IPPROTO_HOPOPTS); #endif #ifdef IPPROTO_ICMP - PyModule_AddIntMacro(m, IPPROTO_ICMP); + ADD_INT_MACRO(m, IPPROTO_ICMP); #else - PyModule_AddIntConstant(m, "IPPROTO_ICMP", 1); + ADD_INT_CONST(m, "IPPROTO_ICMP", 1); #endif #ifdef IPPROTO_IGMP - PyModule_AddIntMacro(m, IPPROTO_IGMP); + ADD_INT_MACRO(m, IPPROTO_IGMP); #endif #ifdef IPPROTO_GGP - PyModule_AddIntMacro(m, IPPROTO_GGP); + ADD_INT_MACRO(m, IPPROTO_GGP); #endif #ifdef IPPROTO_IPV4 - PyModule_AddIntMacro(m, IPPROTO_IPV4); + ADD_INT_MACRO(m, IPPROTO_IPV4); #endif #ifdef IPPROTO_IPV6 - PyModule_AddIntMacro(m, IPPROTO_IPV6); + ADD_INT_MACRO(m, IPPROTO_IPV6); #endif #ifdef IPPROTO_IPIP - PyModule_AddIntMacro(m, IPPROTO_IPIP); + ADD_INT_MACRO(m, IPPROTO_IPIP); #endif #ifdef IPPROTO_TCP - PyModule_AddIntMacro(m, IPPROTO_TCP); + ADD_INT_MACRO(m, IPPROTO_TCP); #else - PyModule_AddIntConstant(m, "IPPROTO_TCP", 6); + ADD_INT_CONST(m, "IPPROTO_TCP", 6); #endif #ifdef IPPROTO_EGP - PyModule_AddIntMacro(m, IPPROTO_EGP); + ADD_INT_MACRO(m, IPPROTO_EGP); #endif #ifdef IPPROTO_PUP - PyModule_AddIntMacro(m, IPPROTO_PUP); + ADD_INT_MACRO(m, IPPROTO_PUP); #endif #ifdef IPPROTO_UDP - PyModule_AddIntMacro(m, IPPROTO_UDP); + ADD_INT_MACRO(m, IPPROTO_UDP); #else - PyModule_AddIntConstant(m, "IPPROTO_UDP", 17); + ADD_INT_CONST(m, "IPPROTO_UDP", 17); #endif #ifdef IPPROTO_UDPLITE - PyModule_AddIntMacro(m, IPPROTO_UDPLITE); + ADD_INT_MACRO(m, IPPROTO_UDPLITE); #ifndef UDPLITE_SEND_CSCOV #define UDPLITE_SEND_CSCOV 10 #endif - PyModule_AddIntMacro(m, UDPLITE_SEND_CSCOV); + ADD_INT_MACRO(m, UDPLITE_SEND_CSCOV); #ifndef UDPLITE_RECV_CSCOV #define UDPLITE_RECV_CSCOV 11 #endif - PyModule_AddIntMacro(m, UDPLITE_RECV_CSCOV); + ADD_INT_MACRO(m, UDPLITE_RECV_CSCOV); #endif #ifdef IPPROTO_IDP - PyModule_AddIntMacro(m, IPPROTO_IDP); + ADD_INT_MACRO(m, IPPROTO_IDP); #endif #ifdef IPPROTO_HELLO - PyModule_AddIntMacro(m, IPPROTO_HELLO); + ADD_INT_MACRO(m, IPPROTO_HELLO); #endif #ifdef IPPROTO_ND - PyModule_AddIntMacro(m, IPPROTO_ND); + ADD_INT_MACRO(m, IPPROTO_ND); #endif #ifdef IPPROTO_TP - PyModule_AddIntMacro(m, IPPROTO_TP); + ADD_INT_MACRO(m, IPPROTO_TP); #endif #ifdef IPPROTO_ROUTING - PyModule_AddIntMacro(m, IPPROTO_ROUTING); + ADD_INT_MACRO(m, IPPROTO_ROUTING); #endif #ifdef IPPROTO_FRAGMENT - PyModule_AddIntMacro(m, IPPROTO_FRAGMENT); + ADD_INT_MACRO(m, IPPROTO_FRAGMENT); #endif #ifdef IPPROTO_RSVP - PyModule_AddIntMacro(m, IPPROTO_RSVP); + ADD_INT_MACRO(m, IPPROTO_RSVP); #endif #ifdef IPPROTO_GRE - PyModule_AddIntMacro(m, IPPROTO_GRE); + ADD_INT_MACRO(m, IPPROTO_GRE); #endif #ifdef IPPROTO_ESP - PyModule_AddIntMacro(m, IPPROTO_ESP); + ADD_INT_MACRO(m, IPPROTO_ESP); #endif #ifdef IPPROTO_AH - PyModule_AddIntMacro(m, IPPROTO_AH); + ADD_INT_MACRO(m, IPPROTO_AH); #endif #ifdef IPPROTO_MOBILE - PyModule_AddIntMacro(m, IPPROTO_MOBILE); + ADD_INT_MACRO(m, IPPROTO_MOBILE); #endif #ifdef IPPROTO_ICMPV6 - PyModule_AddIntMacro(m, IPPROTO_ICMPV6); + ADD_INT_MACRO(m, IPPROTO_ICMPV6); #endif #ifdef IPPROTO_NONE - PyModule_AddIntMacro(m, IPPROTO_NONE); + ADD_INT_MACRO(m, IPPROTO_NONE); #endif #ifdef IPPROTO_DSTOPTS - PyModule_AddIntMacro(m, IPPROTO_DSTOPTS); + ADD_INT_MACRO(m, IPPROTO_DSTOPTS); #endif #ifdef IPPROTO_XTP - PyModule_AddIntMacro(m, IPPROTO_XTP); + ADD_INT_MACRO(m, IPPROTO_XTP); #endif #ifdef IPPROTO_EON - PyModule_AddIntMacro(m, IPPROTO_EON); + ADD_INT_MACRO(m, IPPROTO_EON); #endif #ifdef IPPROTO_PIM - PyModule_AddIntMacro(m, IPPROTO_PIM); + ADD_INT_MACRO(m, IPPROTO_PIM); #endif #ifdef IPPROTO_IPCOMP - PyModule_AddIntMacro(m, IPPROTO_IPCOMP); + ADD_INT_MACRO(m, IPPROTO_IPCOMP); #endif #ifdef IPPROTO_VRRP - PyModule_AddIntMacro(m, IPPROTO_VRRP); + ADD_INT_MACRO(m, IPPROTO_VRRP); #endif #ifdef IPPROTO_SCTP - PyModule_AddIntMacro(m, IPPROTO_SCTP); + ADD_INT_MACRO(m, IPPROTO_SCTP); #endif #ifdef IPPROTO_BIP - PyModule_AddIntMacro(m, IPPROTO_BIP); + ADD_INT_MACRO(m, IPPROTO_BIP); #endif #ifdef IPPROTO_MPTCP - PyModule_AddIntMacro(m, IPPROTO_MPTCP); + ADD_INT_MACRO(m, IPPROTO_MPTCP); #endif /**/ #ifdef IPPROTO_RAW - PyModule_AddIntMacro(m, IPPROTO_RAW); + ADD_INT_MACRO(m, IPPROTO_RAW); #else - PyModule_AddIntConstant(m, "IPPROTO_RAW", 255); + ADD_INT_CONST(m, "IPPROTO_RAW", 255); #endif #ifdef IPPROTO_MAX - PyModule_AddIntMacro(m, IPPROTO_MAX); + ADD_INT_MACRO(m, IPPROTO_MAX); #endif #ifdef MS_WINDOWS - PyModule_AddIntMacro(m, IPPROTO_ICLFXBM); - PyModule_AddIntMacro(m, IPPROTO_ST); - PyModule_AddIntMacro(m, IPPROTO_CBT); - PyModule_AddIntMacro(m, IPPROTO_IGP); - PyModule_AddIntMacro(m, IPPROTO_RDP); - PyModule_AddIntMacro(m, IPPROTO_PGM); - PyModule_AddIntMacro(m, IPPROTO_L2TP); - PyModule_AddIntMacro(m, IPPROTO_SCTP); + ADD_INT_MACRO(m, IPPROTO_ICLFXBM); + ADD_INT_MACRO(m, IPPROTO_ST); + ADD_INT_MACRO(m, IPPROTO_CBT); + ADD_INT_MACRO(m, IPPROTO_IGP); + ADD_INT_MACRO(m, IPPROTO_RDP); + ADD_INT_MACRO(m, IPPROTO_PGM); + ADD_INT_MACRO(m, IPPROTO_L2TP); + ADD_INT_MACRO(m, IPPROTO_SCTP); #endif #ifdef SYSPROTO_CONTROL - PyModule_AddIntMacro(m, SYSPROTO_CONTROL); + ADD_INT_MACRO(m, SYSPROTO_CONTROL); #endif /* Some port configuration */ #ifdef IPPORT_RESERVED - PyModule_AddIntMacro(m, IPPORT_RESERVED); + ADD_INT_MACRO(m, IPPORT_RESERVED); #else - PyModule_AddIntConstant(m, "IPPORT_RESERVED", 1024); + ADD_INT_CONST(m, "IPPORT_RESERVED", 1024); #endif #ifdef IPPORT_USERRESERVED - PyModule_AddIntMacro(m, IPPORT_USERRESERVED); + ADD_INT_MACRO(m, IPPORT_USERRESERVED); #else - PyModule_AddIntConstant(m, "IPPORT_USERRESERVED", 5000); + ADD_INT_CONST(m, "IPPORT_USERRESERVED", 5000); #endif /* Some reserved IP v.4 addresses */ #ifdef INADDR_ANY - PyModule_AddIntMacro(m, INADDR_ANY); + ADD_INT_MACRO(m, INADDR_ANY); #else - PyModule_AddIntConstant(m, "INADDR_ANY", 0x00000000); + ADD_INT_CONST(m, "INADDR_ANY", 0x00000000); #endif #ifdef INADDR_BROADCAST - PyModule_AddIntMacro(m, INADDR_BROADCAST); + ADD_INT_MACRO(m, INADDR_BROADCAST); #else - PyModule_AddIntConstant(m, "INADDR_BROADCAST", 0xffffffff); + ADD_INT_CONST(m, "INADDR_BROADCAST", 0xffffffff); #endif #ifdef INADDR_LOOPBACK - PyModule_AddIntMacro(m, INADDR_LOOPBACK); + ADD_INT_MACRO(m, INADDR_LOOPBACK); #else - PyModule_AddIntConstant(m, "INADDR_LOOPBACK", 0x7F000001); + ADD_INT_CONST(m, "INADDR_LOOPBACK", 0x7F000001); #endif #ifdef INADDR_UNSPEC_GROUP - PyModule_AddIntMacro(m, INADDR_UNSPEC_GROUP); + ADD_INT_MACRO(m, INADDR_UNSPEC_GROUP); #else - PyModule_AddIntConstant(m, "INADDR_UNSPEC_GROUP", 0xe0000000); + ADD_INT_CONST(m, "INADDR_UNSPEC_GROUP", 0xe0000000); #endif #ifdef INADDR_ALLHOSTS_GROUP - PyModule_AddIntConstant(m, "INADDR_ALLHOSTS_GROUP", + ADD_INT_CONST(m, "INADDR_ALLHOSTS_GROUP", INADDR_ALLHOSTS_GROUP); #else - PyModule_AddIntConstant(m, "INADDR_ALLHOSTS_GROUP", 0xe0000001); + ADD_INT_CONST(m, "INADDR_ALLHOSTS_GROUP", 0xe0000001); #endif #ifdef INADDR_MAX_LOCAL_GROUP - PyModule_AddIntMacro(m, INADDR_MAX_LOCAL_GROUP); + ADD_INT_MACRO(m, INADDR_MAX_LOCAL_GROUP); #else - PyModule_AddIntConstant(m, "INADDR_MAX_LOCAL_GROUP", 0xe00000ff); + ADD_INT_CONST(m, "INADDR_MAX_LOCAL_GROUP", 0xe00000ff); #endif #ifdef INADDR_NONE - PyModule_AddIntMacro(m, INADDR_NONE); + ADD_INT_MACRO(m, INADDR_NONE); #else - PyModule_AddIntConstant(m, "INADDR_NONE", 0xffffffff); + ADD_INT_CONST(m, "INADDR_NONE", 0xffffffff); #endif /* IPv4 [gs]etsockopt options */ #ifdef IP_OPTIONS - PyModule_AddIntMacro(m, IP_OPTIONS); + ADD_INT_MACRO(m, IP_OPTIONS); #endif #ifdef IP_HDRINCL - PyModule_AddIntMacro(m, IP_HDRINCL); + ADD_INT_MACRO(m, IP_HDRINCL); #endif #ifdef IP_TOS - PyModule_AddIntMacro(m, IP_TOS); + ADD_INT_MACRO(m, IP_TOS); #endif #ifdef IP_TTL - PyModule_AddIntMacro(m, IP_TTL); + ADD_INT_MACRO(m, IP_TTL); #endif #ifdef IP_RECVOPTS - PyModule_AddIntMacro(m, IP_RECVOPTS); + ADD_INT_MACRO(m, IP_RECVOPTS); #endif #ifdef IP_RECVRETOPTS - PyModule_AddIntMacro(m, IP_RECVRETOPTS); + ADD_INT_MACRO(m, IP_RECVRETOPTS); #endif #ifdef IP_RECVTOS - PyModule_AddIntMacro(m, IP_RECVTOS); + ADD_INT_MACRO(m, IP_RECVTOS); #endif #ifdef IP_RECVDSTADDR - PyModule_AddIntMacro(m, IP_RECVDSTADDR); + ADD_INT_MACRO(m, IP_RECVDSTADDR); #endif #ifdef IP_RETOPTS - PyModule_AddIntMacro(m, IP_RETOPTS); + ADD_INT_MACRO(m, IP_RETOPTS); #endif #ifdef IP_MULTICAST_IF - PyModule_AddIntMacro(m, IP_MULTICAST_IF); + ADD_INT_MACRO(m, IP_MULTICAST_IF); #endif #ifdef IP_MULTICAST_TTL - PyModule_AddIntMacro(m, IP_MULTICAST_TTL); + ADD_INT_MACRO(m, IP_MULTICAST_TTL); #endif #ifdef IP_MULTICAST_LOOP - PyModule_AddIntMacro(m, IP_MULTICAST_LOOP); + ADD_INT_MACRO(m, IP_MULTICAST_LOOP); #endif #ifdef IP_ADD_MEMBERSHIP - PyModule_AddIntMacro(m, IP_ADD_MEMBERSHIP); + ADD_INT_MACRO(m, IP_ADD_MEMBERSHIP); #endif #ifdef IP_DROP_MEMBERSHIP - PyModule_AddIntMacro(m, IP_DROP_MEMBERSHIP); + ADD_INT_MACRO(m, IP_DROP_MEMBERSHIP); #endif #ifdef IP_DEFAULT_MULTICAST_TTL - PyModule_AddIntMacro(m, IP_DEFAULT_MULTICAST_TTL); + ADD_INT_MACRO(m, IP_DEFAULT_MULTICAST_TTL); #endif #ifdef IP_DEFAULT_MULTICAST_LOOP - PyModule_AddIntMacro(m, IP_DEFAULT_MULTICAST_LOOP); + ADD_INT_MACRO(m, IP_DEFAULT_MULTICAST_LOOP); #endif #ifdef IP_MAX_MEMBERSHIPS - PyModule_AddIntMacro(m, IP_MAX_MEMBERSHIPS); + ADD_INT_MACRO(m, IP_MAX_MEMBERSHIPS); #endif #ifdef IP_TRANSPARENT - PyModule_AddIntMacro(m, IP_TRANSPARENT); + ADD_INT_MACRO(m, IP_TRANSPARENT); #endif #ifdef IP_PKTINFO - PyModule_AddIntMacro(m, IP_PKTINFO); + ADD_INT_MACRO(m, IP_PKTINFO); #endif #ifdef IP_BIND_ADDRESS_NO_PORT - PyModule_AddIntMacro(m, IP_BIND_ADDRESS_NO_PORT); + ADD_INT_MACRO(m, IP_BIND_ADDRESS_NO_PORT); #endif /* IPv6 [gs]etsockopt options, defined in RFC2553 */ #ifdef IPV6_JOIN_GROUP - PyModule_AddIntMacro(m, IPV6_JOIN_GROUP); + ADD_INT_MACRO(m, IPV6_JOIN_GROUP); #endif #ifdef IPV6_LEAVE_GROUP - PyModule_AddIntMacro(m, IPV6_LEAVE_GROUP); + ADD_INT_MACRO(m, IPV6_LEAVE_GROUP); #endif #ifdef IPV6_MULTICAST_HOPS - PyModule_AddIntMacro(m, IPV6_MULTICAST_HOPS); + ADD_INT_MACRO(m, IPV6_MULTICAST_HOPS); #endif #ifdef IPV6_MULTICAST_IF - PyModule_AddIntMacro(m, IPV6_MULTICAST_IF); + ADD_INT_MACRO(m, IPV6_MULTICAST_IF); #endif #ifdef IPV6_MULTICAST_LOOP - PyModule_AddIntMacro(m, IPV6_MULTICAST_LOOP); + ADD_INT_MACRO(m, IPV6_MULTICAST_LOOP); #endif #ifdef IPV6_UNICAST_HOPS - PyModule_AddIntMacro(m, IPV6_UNICAST_HOPS); + ADD_INT_MACRO(m, IPV6_UNICAST_HOPS); #endif /* Additional IPV6 socket options, defined in RFC 3493 */ #ifdef IPV6_V6ONLY - PyModule_AddIntMacro(m, IPV6_V6ONLY); + ADD_INT_MACRO(m, IPV6_V6ONLY); #endif /* Advanced IPV6 socket options, from RFC 3542 */ #ifdef IPV6_CHECKSUM - PyModule_AddIntMacro(m, IPV6_CHECKSUM); + ADD_INT_MACRO(m, IPV6_CHECKSUM); #endif #ifdef IPV6_DONTFRAG - PyModule_AddIntMacro(m, IPV6_DONTFRAG); + ADD_INT_MACRO(m, IPV6_DONTFRAG); #endif #ifdef IPV6_DSTOPTS - PyModule_AddIntMacro(m, IPV6_DSTOPTS); + ADD_INT_MACRO(m, IPV6_DSTOPTS); #endif #ifdef IPV6_HOPLIMIT - PyModule_AddIntMacro(m, IPV6_HOPLIMIT); + ADD_INT_MACRO(m, IPV6_HOPLIMIT); #endif #ifdef IPV6_HOPOPTS - PyModule_AddIntMacro(m, IPV6_HOPOPTS); + ADD_INT_MACRO(m, IPV6_HOPOPTS); #endif #ifdef IPV6_NEXTHOP - PyModule_AddIntMacro(m, IPV6_NEXTHOP); + ADD_INT_MACRO(m, IPV6_NEXTHOP); #endif #ifdef IPV6_PATHMTU - PyModule_AddIntMacro(m, IPV6_PATHMTU); + ADD_INT_MACRO(m, IPV6_PATHMTU); #endif #ifdef IPV6_PKTINFO - PyModule_AddIntMacro(m, IPV6_PKTINFO); + ADD_INT_MACRO(m, IPV6_PKTINFO); #endif #ifdef IPV6_RECVDSTOPTS - PyModule_AddIntMacro(m, IPV6_RECVDSTOPTS); + ADD_INT_MACRO(m, IPV6_RECVDSTOPTS); #endif #ifdef IPV6_RECVHOPLIMIT - PyModule_AddIntMacro(m, IPV6_RECVHOPLIMIT); + ADD_INT_MACRO(m, IPV6_RECVHOPLIMIT); #endif #ifdef IPV6_RECVHOPOPTS - PyModule_AddIntMacro(m, IPV6_RECVHOPOPTS); + ADD_INT_MACRO(m, IPV6_RECVHOPOPTS); #endif #ifdef IPV6_RECVPKTINFO - PyModule_AddIntMacro(m, IPV6_RECVPKTINFO); + ADD_INT_MACRO(m, IPV6_RECVPKTINFO); #endif #ifdef IPV6_RECVRTHDR - PyModule_AddIntMacro(m, IPV6_RECVRTHDR); + ADD_INT_MACRO(m, IPV6_RECVRTHDR); #endif #ifdef IPV6_RECVTCLASS - PyModule_AddIntMacro(m, IPV6_RECVTCLASS); + ADD_INT_MACRO(m, IPV6_RECVTCLASS); #endif #ifdef IPV6_RTHDR - PyModule_AddIntMacro(m, IPV6_RTHDR); + ADD_INT_MACRO(m, IPV6_RTHDR); #endif #ifdef IPV6_RTHDRDSTOPTS - PyModule_AddIntMacro(m, IPV6_RTHDRDSTOPTS); + ADD_INT_MACRO(m, IPV6_RTHDRDSTOPTS); #endif #ifdef IPV6_RTHDR_TYPE_0 - PyModule_AddIntMacro(m, IPV6_RTHDR_TYPE_0); + ADD_INT_MACRO(m, IPV6_RTHDR_TYPE_0); #endif #ifdef IPV6_RECVPATHMTU - PyModule_AddIntMacro(m, IPV6_RECVPATHMTU); + ADD_INT_MACRO(m, IPV6_RECVPATHMTU); #endif #ifdef IPV6_TCLASS - PyModule_AddIntMacro(m, IPV6_TCLASS); + ADD_INT_MACRO(m, IPV6_TCLASS); #endif #ifdef IPV6_USE_MIN_MTU - PyModule_AddIntMacro(m, IPV6_USE_MIN_MTU); + ADD_INT_MACRO(m, IPV6_USE_MIN_MTU); #endif /* TCP options */ #ifdef TCP_NODELAY - PyModule_AddIntMacro(m, TCP_NODELAY); + ADD_INT_MACRO(m, TCP_NODELAY); #endif #ifdef TCP_MAXSEG - PyModule_AddIntMacro(m, TCP_MAXSEG); + ADD_INT_MACRO(m, TCP_MAXSEG); #endif #ifdef TCP_CORK - PyModule_AddIntMacro(m, TCP_CORK); + ADD_INT_MACRO(m, TCP_CORK); #endif #ifdef TCP_KEEPIDLE - PyModule_AddIntMacro(m, TCP_KEEPIDLE); + ADD_INT_MACRO(m, TCP_KEEPIDLE); #endif /* TCP_KEEPALIVE is OSX's TCP_KEEPIDLE equivalent */ #if defined(__APPLE__) && defined(TCP_KEEPALIVE) - PyModule_AddIntMacro(m, TCP_KEEPALIVE); + ADD_INT_MACRO(m, TCP_KEEPALIVE); #endif #ifdef TCP_KEEPINTVL - PyModule_AddIntMacro(m, TCP_KEEPINTVL); + ADD_INT_MACRO(m, TCP_KEEPINTVL); #endif #ifdef TCP_KEEPCNT - PyModule_AddIntMacro(m, TCP_KEEPCNT); + ADD_INT_MACRO(m, TCP_KEEPCNT); #endif #ifdef TCP_SYNCNT - PyModule_AddIntMacro(m, TCP_SYNCNT); + ADD_INT_MACRO(m, TCP_SYNCNT); #endif #ifdef TCP_LINGER2 - PyModule_AddIntMacro(m, TCP_LINGER2); + ADD_INT_MACRO(m, TCP_LINGER2); #endif #ifdef TCP_DEFER_ACCEPT - PyModule_AddIntMacro(m, TCP_DEFER_ACCEPT); + ADD_INT_MACRO(m, TCP_DEFER_ACCEPT); #endif #ifdef TCP_WINDOW_CLAMP - PyModule_AddIntMacro(m, TCP_WINDOW_CLAMP); + ADD_INT_MACRO(m, TCP_WINDOW_CLAMP); #endif #ifdef TCP_INFO - PyModule_AddIntMacro(m, TCP_INFO); + ADD_INT_MACRO(m, TCP_INFO); #endif #ifdef TCP_CONNECTION_INFO - PyModule_AddIntMacro(m, TCP_CONNECTION_INFO); + ADD_INT_MACRO(m, TCP_CONNECTION_INFO); #endif #ifdef TCP_QUICKACK - PyModule_AddIntMacro(m, TCP_QUICKACK); + ADD_INT_MACRO(m, TCP_QUICKACK); #endif #ifdef TCP_CONGESTION - PyModule_AddIntMacro(m, TCP_CONGESTION); + ADD_INT_MACRO(m, TCP_CONGESTION); #endif #ifdef TCP_MD5SIG - PyModule_AddIntMacro(m, TCP_MD5SIG); + ADD_INT_MACRO(m, TCP_MD5SIG); #endif #ifdef TCP_THIN_LINEAR_TIMEOUTS - PyModule_AddIntMacro(m, TCP_THIN_LINEAR_TIMEOUTS); + ADD_INT_MACRO(m, TCP_THIN_LINEAR_TIMEOUTS); #endif #ifdef TCP_THIN_DUPACK - PyModule_AddIntMacro(m, TCP_THIN_DUPACK); + ADD_INT_MACRO(m, TCP_THIN_DUPACK); #endif #ifdef TCP_USER_TIMEOUT - PyModule_AddIntMacro(m, TCP_USER_TIMEOUT); + ADD_INT_MACRO(m, TCP_USER_TIMEOUT); #endif #ifdef TCP_REPAIR - PyModule_AddIntMacro(m, TCP_REPAIR); + ADD_INT_MACRO(m, TCP_REPAIR); #endif #ifdef TCP_REPAIR_QUEUE - PyModule_AddIntMacro(m, TCP_REPAIR_QUEUE); + ADD_INT_MACRO(m, TCP_REPAIR_QUEUE); #endif #ifdef TCP_QUEUE_SEQ - PyModule_AddIntMacro(m, TCP_QUEUE_SEQ); + ADD_INT_MACRO(m, TCP_QUEUE_SEQ); #endif #ifdef TCP_REPAIR_OPTIONS - PyModule_AddIntMacro(m, TCP_REPAIR_OPTIONS); + ADD_INT_MACRO(m, TCP_REPAIR_OPTIONS); #endif #ifdef TCP_FASTOPEN - PyModule_AddIntMacro(m, TCP_FASTOPEN); + ADD_INT_MACRO(m, TCP_FASTOPEN); #endif #ifdef TCP_TIMESTAMP - PyModule_AddIntMacro(m, TCP_TIMESTAMP); + ADD_INT_MACRO(m, TCP_TIMESTAMP); #endif #ifdef TCP_NOTSENT_LOWAT - PyModule_AddIntMacro(m, TCP_NOTSENT_LOWAT); + ADD_INT_MACRO(m, TCP_NOTSENT_LOWAT); #endif #ifdef TCP_CC_INFO - PyModule_AddIntMacro(m, TCP_CC_INFO); + ADD_INT_MACRO(m, TCP_CC_INFO); #endif #ifdef TCP_SAVE_SYN - PyModule_AddIntMacro(m, TCP_SAVE_SYN); + ADD_INT_MACRO(m, TCP_SAVE_SYN); #endif #ifdef TCP_SAVED_SYN - PyModule_AddIntMacro(m, TCP_SAVED_SYN); + ADD_INT_MACRO(m, TCP_SAVED_SYN); #endif #ifdef TCP_REPAIR_WINDOW - PyModule_AddIntMacro(m, TCP_REPAIR_WINDOW); + ADD_INT_MACRO(m, TCP_REPAIR_WINDOW); #endif #ifdef TCP_FASTOPEN_CONNECT - PyModule_AddIntMacro(m, TCP_FASTOPEN_CONNECT); + ADD_INT_MACRO(m, TCP_FASTOPEN_CONNECT); #endif #ifdef TCP_ULP - PyModule_AddIntMacro(m, TCP_ULP); + ADD_INT_MACRO(m, TCP_ULP); #endif #ifdef TCP_MD5SIG_EXT - PyModule_AddIntMacro(m, TCP_MD5SIG_EXT); + ADD_INT_MACRO(m, TCP_MD5SIG_EXT); #endif #ifdef TCP_FASTOPEN_KEY - PyModule_AddIntMacro(m, TCP_FASTOPEN_KEY); + ADD_INT_MACRO(m, TCP_FASTOPEN_KEY); #endif #ifdef TCP_FASTOPEN_NO_COOKIE - PyModule_AddIntMacro(m, TCP_FASTOPEN_NO_COOKIE); + ADD_INT_MACRO(m, TCP_FASTOPEN_NO_COOKIE); #endif #ifdef TCP_ZEROCOPY_RECEIVE - PyModule_AddIntMacro(m, TCP_ZEROCOPY_RECEIVE); + ADD_INT_MACRO(m, TCP_ZEROCOPY_RECEIVE); #endif #ifdef TCP_INQ - PyModule_AddIntMacro(m, TCP_INQ); + ADD_INT_MACRO(m, TCP_INQ); #endif #ifdef TCP_TX_DELAY - PyModule_AddIntMacro(m, TCP_TX_DELAY); + ADD_INT_MACRO(m, TCP_TX_DELAY); #endif /* IPX options */ #ifdef IPX_TYPE - PyModule_AddIntMacro(m, IPX_TYPE); + ADD_INT_MACRO(m, IPX_TYPE); #endif /* Reliable Datagram Sockets */ #ifdef RDS_CMSG_RDMA_ARGS - PyModule_AddIntMacro(m, RDS_CMSG_RDMA_ARGS); + ADD_INT_MACRO(m, RDS_CMSG_RDMA_ARGS); #endif #ifdef RDS_CMSG_RDMA_DEST - PyModule_AddIntMacro(m, RDS_CMSG_RDMA_DEST); + ADD_INT_MACRO(m, RDS_CMSG_RDMA_DEST); #endif #ifdef RDS_CMSG_RDMA_MAP - PyModule_AddIntMacro(m, RDS_CMSG_RDMA_MAP); + ADD_INT_MACRO(m, RDS_CMSG_RDMA_MAP); #endif #ifdef RDS_CMSG_RDMA_STATUS - PyModule_AddIntMacro(m, RDS_CMSG_RDMA_STATUS); + ADD_INT_MACRO(m, RDS_CMSG_RDMA_STATUS); #endif #ifdef RDS_CMSG_RDMA_UPDATE - PyModule_AddIntMacro(m, RDS_CMSG_RDMA_UPDATE); + ADD_INT_MACRO(m, RDS_CMSG_RDMA_UPDATE); #endif #ifdef RDS_RDMA_READWRITE - PyModule_AddIntMacro(m, RDS_RDMA_READWRITE); + ADD_INT_MACRO(m, RDS_RDMA_READWRITE); #endif #ifdef RDS_RDMA_FENCE - PyModule_AddIntMacro(m, RDS_RDMA_FENCE); + ADD_INT_MACRO(m, RDS_RDMA_FENCE); #endif #ifdef RDS_RDMA_INVALIDATE - PyModule_AddIntMacro(m, RDS_RDMA_INVALIDATE); + ADD_INT_MACRO(m, RDS_RDMA_INVALIDATE); #endif #ifdef RDS_RDMA_USE_ONCE - PyModule_AddIntMacro(m, RDS_RDMA_USE_ONCE); + ADD_INT_MACRO(m, RDS_RDMA_USE_ONCE); #endif #ifdef RDS_RDMA_DONTWAIT - PyModule_AddIntMacro(m, RDS_RDMA_DONTWAIT); + ADD_INT_MACRO(m, RDS_RDMA_DONTWAIT); #endif #ifdef RDS_RDMA_NOTIFY_ME - PyModule_AddIntMacro(m, RDS_RDMA_NOTIFY_ME); + ADD_INT_MACRO(m, RDS_RDMA_NOTIFY_ME); #endif #ifdef RDS_RDMA_SILENT - PyModule_AddIntMacro(m, RDS_RDMA_SILENT); + ADD_INT_MACRO(m, RDS_RDMA_SILENT); #endif /* get{addr,name}info parameters */ #ifdef EAI_ADDRFAMILY - PyModule_AddIntMacro(m, EAI_ADDRFAMILY); + ADD_INT_MACRO(m, EAI_ADDRFAMILY); #endif #ifdef EAI_AGAIN - PyModule_AddIntMacro(m, EAI_AGAIN); + ADD_INT_MACRO(m, EAI_AGAIN); #endif #ifdef EAI_BADFLAGS - PyModule_AddIntMacro(m, EAI_BADFLAGS); + ADD_INT_MACRO(m, EAI_BADFLAGS); #endif #ifdef EAI_FAIL - PyModule_AddIntMacro(m, EAI_FAIL); + ADD_INT_MACRO(m, EAI_FAIL); #endif #ifdef EAI_FAMILY - PyModule_AddIntMacro(m, EAI_FAMILY); + ADD_INT_MACRO(m, EAI_FAMILY); #endif #ifdef EAI_MEMORY - PyModule_AddIntMacro(m, EAI_MEMORY); + ADD_INT_MACRO(m, EAI_MEMORY); #endif #ifdef EAI_NODATA - PyModule_AddIntMacro(m, EAI_NODATA); + ADD_INT_MACRO(m, EAI_NODATA); #endif #ifdef EAI_NONAME - PyModule_AddIntMacro(m, EAI_NONAME); + ADD_INT_MACRO(m, EAI_NONAME); #endif #ifdef EAI_OVERFLOW - PyModule_AddIntMacro(m, EAI_OVERFLOW); + ADD_INT_MACRO(m, EAI_OVERFLOW); #endif #ifdef EAI_SERVICE - PyModule_AddIntMacro(m, EAI_SERVICE); + ADD_INT_MACRO(m, EAI_SERVICE); #endif #ifdef EAI_SOCKTYPE - PyModule_AddIntMacro(m, EAI_SOCKTYPE); + ADD_INT_MACRO(m, EAI_SOCKTYPE); #endif #ifdef EAI_SYSTEM - PyModule_AddIntMacro(m, EAI_SYSTEM); + ADD_INT_MACRO(m, EAI_SYSTEM); #endif #ifdef EAI_BADHINTS - PyModule_AddIntMacro(m, EAI_BADHINTS); + ADD_INT_MACRO(m, EAI_BADHINTS); #endif #ifdef EAI_PROTOCOL - PyModule_AddIntMacro(m, EAI_PROTOCOL); + ADD_INT_MACRO(m, EAI_PROTOCOL); #endif #ifdef EAI_MAX - PyModule_AddIntMacro(m, EAI_MAX); + ADD_INT_MACRO(m, EAI_MAX); #endif #ifdef AI_PASSIVE - PyModule_AddIntMacro(m, AI_PASSIVE); + ADD_INT_MACRO(m, AI_PASSIVE); #endif #ifdef AI_CANONNAME - PyModule_AddIntMacro(m, AI_CANONNAME); + ADD_INT_MACRO(m, AI_CANONNAME); #endif #ifdef AI_NUMERICHOST - PyModule_AddIntMacro(m, AI_NUMERICHOST); + ADD_INT_MACRO(m, AI_NUMERICHOST); #endif #ifdef AI_NUMERICSERV - PyModule_AddIntMacro(m, AI_NUMERICSERV); + ADD_INT_MACRO(m, AI_NUMERICSERV); #endif #ifdef AI_MASK - PyModule_AddIntMacro(m, AI_MASK); + ADD_INT_MACRO(m, AI_MASK); #endif #ifdef AI_ALL - PyModule_AddIntMacro(m, AI_ALL); + ADD_INT_MACRO(m, AI_ALL); #endif #ifdef AI_V4MAPPED_CFG - PyModule_AddIntMacro(m, AI_V4MAPPED_CFG); + ADD_INT_MACRO(m, AI_V4MAPPED_CFG); #endif #ifdef AI_ADDRCONFIG - PyModule_AddIntMacro(m, AI_ADDRCONFIG); + ADD_INT_MACRO(m, AI_ADDRCONFIG); #endif #ifdef AI_V4MAPPED - PyModule_AddIntMacro(m, AI_V4MAPPED); + ADD_INT_MACRO(m, AI_V4MAPPED); #endif #ifdef AI_DEFAULT - PyModule_AddIntMacro(m, AI_DEFAULT); + ADD_INT_MACRO(m, AI_DEFAULT); #endif #ifdef NI_MAXHOST - PyModule_AddIntMacro(m, NI_MAXHOST); + ADD_INT_MACRO(m, NI_MAXHOST); #endif #ifdef NI_MAXSERV - PyModule_AddIntMacro(m, NI_MAXSERV); + ADD_INT_MACRO(m, NI_MAXSERV); #endif #ifdef NI_NOFQDN - PyModule_AddIntMacro(m, NI_NOFQDN); + ADD_INT_MACRO(m, NI_NOFQDN); #endif #ifdef NI_NUMERICHOST - PyModule_AddIntMacro(m, NI_NUMERICHOST); + ADD_INT_MACRO(m, NI_NUMERICHOST); #endif #ifdef NI_NAMEREQD - PyModule_AddIntMacro(m, NI_NAMEREQD); + ADD_INT_MACRO(m, NI_NAMEREQD); #endif #ifdef NI_NUMERICSERV - PyModule_AddIntMacro(m, NI_NUMERICSERV); + ADD_INT_MACRO(m, NI_NUMERICSERV); #endif #ifdef NI_DGRAM - PyModule_AddIntMacro(m, NI_DGRAM); + ADD_INT_MACRO(m, NI_DGRAM); #endif /* shutdown() parameters */ #ifdef SHUT_RD - PyModule_AddIntMacro(m, SHUT_RD); + ADD_INT_MACRO(m, SHUT_RD); #elif defined(SD_RECEIVE) - PyModule_AddIntConstant(m, "SHUT_RD", SD_RECEIVE); + ADD_INT_CONST(m, "SHUT_RD", SD_RECEIVE); #else - PyModule_AddIntConstant(m, "SHUT_RD", 0); + ADD_INT_CONST(m, "SHUT_RD", 0); #endif #ifdef SHUT_WR - PyModule_AddIntMacro(m, SHUT_WR); + ADD_INT_MACRO(m, SHUT_WR); #elif defined(SD_SEND) - PyModule_AddIntConstant(m, "SHUT_WR", SD_SEND); + ADD_INT_CONST(m, "SHUT_WR", SD_SEND); #else - PyModule_AddIntConstant(m, "SHUT_WR", 1); + ADD_INT_CONST(m, "SHUT_WR", 1); #endif #ifdef SHUT_RDWR - PyModule_AddIntMacro(m, SHUT_RDWR); + ADD_INT_MACRO(m, SHUT_RDWR); #elif defined(SD_BOTH) - PyModule_AddIntConstant(m, "SHUT_RDWR", SD_BOTH); + ADD_INT_CONST(m, "SHUT_RDWR", SD_BOTH); #else - PyModule_AddIntConstant(m, "SHUT_RDWR", 2); + ADD_INT_CONST(m, "SHUT_RDWR", 2); #endif #ifdef SIO_RCVALL @@ -8741,22 +8774,26 @@ PyInit__socket(void) #endif }; int i; - for(i = 0; i https://github.com/python/cpython/commit/26c65980dc6d842879d133165bb7c461d98cc6c7 commit: 26c65980dc6d842879d133165bb7c461d98cc6c7 branch: main author: Russell Keith-Magee committer: carljm date: 2023-04-07T20:09:00-06:00 summary: gh-103329: Add regression test for PropertyMock with side effect (#103358) files: A Misc/NEWS.d/next/Tests/2023-04-08-00-50-23.gh-issue-103329.M38tqF.rst M Lib/test/test_unittest/testmock/testhelpers.py diff --git a/Lib/test/test_unittest/testmock/testhelpers.py b/Lib/test/test_unittest/testmock/testhelpers.py index 9e7ec5d62d5d..dc4d004cda8a 100644 --- a/Lib/test/test_unittest/testmock/testhelpers.py +++ b/Lib/test/test_unittest/testmock/testhelpers.py @@ -1077,7 +1077,7 @@ def test_propertymock(self): p.stop() - def test_propertymock_returnvalue(self): + def test_propertymock_bare(self): m = MagicMock() p = PropertyMock() type(m).foo = p @@ -1088,6 +1088,27 @@ def test_propertymock_returnvalue(self): self.assertNotIsInstance(returned, PropertyMock) + def test_propertymock_returnvalue(self): + m = MagicMock() + p = PropertyMock(return_value=42) + type(m).foo = p + + returned = m.foo + p.assert_called_once_with() + self.assertEqual(returned, 42) + self.assertNotIsInstance(returned, PropertyMock) + + + def test_propertymock_side_effect(self): + m = MagicMock() + p = PropertyMock(side_effect=ValueError) + type(m).foo = p + + with self.assertRaises(ValueError): + m.foo + p.assert_called_once_with() + + class TestCallablePredicate(unittest.TestCase): def test_type(self): diff --git a/Misc/NEWS.d/next/Tests/2023-04-08-00-50-23.gh-issue-103329.M38tqF.rst b/Misc/NEWS.d/next/Tests/2023-04-08-00-50-23.gh-issue-103329.M38tqF.rst new file mode 100644 index 000000000000..79448ed72804 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-04-08-00-50-23.gh-issue-103329.M38tqF.rst @@ -0,0 +1 @@ +Regression tests for the behaviour of ``unittest.mock.PropertyMock`` were added. From webhook-mailer at python.org Sat Apr 8 03:01:50 2023 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Apr 2023 07:01:50 -0000 Subject: [Python-checkins] gh-103329: Add regression test for PropertyMock with side effect (GH-103358) Message-ID: https://github.com/python/cpython/commit/29a1e89c9fbfaf409cee3d6fada9473a324ac1c8 commit: 29a1e89c9fbfaf409cee3d6fada9473a324ac1c8 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-08T00:01:20-07:00 summary: gh-103329: Add regression test for PropertyMock with side effect (GH-103358) (cherry picked from commit 26c65980dc6d842879d133165bb7c461d98cc6c7) Co-authored-by: Russell Keith-Magee files: A Misc/NEWS.d/next/Tests/2023-04-08-00-50-23.gh-issue-103329.M38tqF.rst M Lib/unittest/test/testmock/testhelpers.py diff --git a/Lib/unittest/test/testmock/testhelpers.py b/Lib/unittest/test/testmock/testhelpers.py index 9e7ec5d62d5d..dc4d004cda8a 100644 --- a/Lib/unittest/test/testmock/testhelpers.py +++ b/Lib/unittest/test/testmock/testhelpers.py @@ -1077,7 +1077,7 @@ def test_propertymock(self): p.stop() - def test_propertymock_returnvalue(self): + def test_propertymock_bare(self): m = MagicMock() p = PropertyMock() type(m).foo = p @@ -1088,6 +1088,27 @@ def test_propertymock_returnvalue(self): self.assertNotIsInstance(returned, PropertyMock) + def test_propertymock_returnvalue(self): + m = MagicMock() + p = PropertyMock(return_value=42) + type(m).foo = p + + returned = m.foo + p.assert_called_once_with() + self.assertEqual(returned, 42) + self.assertNotIsInstance(returned, PropertyMock) + + + def test_propertymock_side_effect(self): + m = MagicMock() + p = PropertyMock(side_effect=ValueError) + type(m).foo = p + + with self.assertRaises(ValueError): + m.foo + p.assert_called_once_with() + + class TestCallablePredicate(unittest.TestCase): def test_type(self): diff --git a/Misc/NEWS.d/next/Tests/2023-04-08-00-50-23.gh-issue-103329.M38tqF.rst b/Misc/NEWS.d/next/Tests/2023-04-08-00-50-23.gh-issue-103329.M38tqF.rst new file mode 100644 index 000000000000..79448ed72804 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-04-08-00-50-23.gh-issue-103329.M38tqF.rst @@ -0,0 +1 @@ +Regression tests for the behaviour of ``unittest.mock.PropertyMock`` were added. From webhook-mailer at python.org Sat Apr 8 03:04:30 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Sat, 08 Apr 2023 07:04:30 -0000 Subject: [Python-checkins] gh-102809: Remove gdbinit mention in Misc/README (#103269) Message-ID: https://github.com/python/cpython/commit/13774969f78de0435da4efbdf21f1130a7a71964 commit: 13774969f78de0435da4efbdf21f1130a7a71964 branch: main author: Tom?? Hrn?iar committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-04-08T00:04:23-07:00 summary: gh-102809: Remove gdbinit mention in Misc/README (#103269) files: M Misc/README diff --git a/Misc/README b/Misc/README index e4dd2005411a..3dab768ba1a7 100644 --- a/Misc/README +++ b/Misc/README @@ -8,7 +8,6 @@ Files found here ---------------- ACKS Acknowledgements -gdbinit Handy stuff to put in your .gdbinit file, if you use gdb HISTORY News from previous releases -- oldest last indent.pro GNU indent profile approximating my C style NEWS News for this release (for some meaning of "this") From webhook-mailer at python.org Sat Apr 8 03:37:56 2023 From: webhook-mailer at python.org (hugovk) Date: Sat, 08 Apr 2023 07:37:56 -0000 Subject: [Python-checkins] gh-75729: Fix os.spawn tests not handling spaces on Windows (#99150) Message-ID: https://github.com/python/cpython/commit/a34c79623877a7ed0c86a6d48ddccffa0de76836 commit: a34c79623877a7ed0c86a6d48ddccffa0de76836 branch: main author: C.A.M. Gerlach committer: hugovk date: 2023-04-08T10:37:23+03:00 summary: gh-75729: Fix os.spawn tests not handling spaces on Windows (#99150) * Quote paths in os.spawn tests on Windows so they work with spaces * Add NEWS entry for os spawn test fix * Fix code style to avoid double negative in os.spawn tests Co-authored-by: Jelle Zijlstra --------- Co-authored-by: Jelle Zijlstra files: A Misc/NEWS.d/next/Tests/2022-11-06-18-42-38.gh-issue-75729.uGYJrv.rst M Lib/test/test_os.py diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 74ece3ffb4ed..584cc05ca82a 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -3214,6 +3214,14 @@ def kill_process(pid): @support.requires_subprocess() class SpawnTests(unittest.TestCase): + @staticmethod + def quote_args(args): + # On Windows, os.spawn* simply joins arguments with spaces: + # arguments need to be quoted + if os.name != 'nt': + return args + return [f'"{arg}"' if " " in arg.strip() else arg for arg in args] + def create_args(self, *, with_env=False, use_bytes=False): self.exitcode = 17 @@ -3234,115 +3242,118 @@ def create_args(self, *, with_env=False, use_bytes=False): with open(filename, "w", encoding="utf-8") as fp: fp.write(code) - args = [sys.executable, filename] + program = sys.executable + args = self.quote_args([program, filename]) if use_bytes: + program = os.fsencode(program) args = [os.fsencode(a) for a in args] self.env = {os.fsencode(k): os.fsencode(v) for k, v in self.env.items()} - return args + return program, args @requires_os_func('spawnl') def test_spawnl(self): - args = self.create_args() - exitcode = os.spawnl(os.P_WAIT, args[0], *args) + program, args = self.create_args() + exitcode = os.spawnl(os.P_WAIT, program, *args) self.assertEqual(exitcode, self.exitcode) @requires_os_func('spawnle') def test_spawnle(self): - args = self.create_args(with_env=True) - exitcode = os.spawnle(os.P_WAIT, args[0], *args, self.env) + program, args = self.create_args(with_env=True) + exitcode = os.spawnle(os.P_WAIT, program, *args, self.env) self.assertEqual(exitcode, self.exitcode) @requires_os_func('spawnlp') def test_spawnlp(self): - args = self.create_args() - exitcode = os.spawnlp(os.P_WAIT, args[0], *args) + program, args = self.create_args() + exitcode = os.spawnlp(os.P_WAIT, program, *args) self.assertEqual(exitcode, self.exitcode) @requires_os_func('spawnlpe') def test_spawnlpe(self): - args = self.create_args(with_env=True) - exitcode = os.spawnlpe(os.P_WAIT, args[0], *args, self.env) + program, args = self.create_args(with_env=True) + exitcode = os.spawnlpe(os.P_WAIT, program, *args, self.env) self.assertEqual(exitcode, self.exitcode) @requires_os_func('spawnv') def test_spawnv(self): - args = self.create_args() - exitcode = os.spawnv(os.P_WAIT, args[0], args) + program, args = self.create_args() + exitcode = os.spawnv(os.P_WAIT, program, args) self.assertEqual(exitcode, self.exitcode) # Test for PyUnicode_FSConverter() - exitcode = os.spawnv(os.P_WAIT, FakePath(args[0]), args) + exitcode = os.spawnv(os.P_WAIT, FakePath(program), args) self.assertEqual(exitcode, self.exitcode) @requires_os_func('spawnve') def test_spawnve(self): - args = self.create_args(with_env=True) - exitcode = os.spawnve(os.P_WAIT, args[0], args, self.env) + program, args = self.create_args(with_env=True) + exitcode = os.spawnve(os.P_WAIT, program, args, self.env) self.assertEqual(exitcode, self.exitcode) @requires_os_func('spawnvp') def test_spawnvp(self): - args = self.create_args() - exitcode = os.spawnvp(os.P_WAIT, args[0], args) + program, args = self.create_args() + exitcode = os.spawnvp(os.P_WAIT, program, args) self.assertEqual(exitcode, self.exitcode) @requires_os_func('spawnvpe') def test_spawnvpe(self): - args = self.create_args(with_env=True) - exitcode = os.spawnvpe(os.P_WAIT, args[0], args, self.env) + program, args = self.create_args(with_env=True) + exitcode = os.spawnvpe(os.P_WAIT, program, args, self.env) self.assertEqual(exitcode, self.exitcode) @requires_os_func('spawnv') def test_nowait(self): - args = self.create_args() - pid = os.spawnv(os.P_NOWAIT, args[0], args) + program, args = self.create_args() + pid = os.spawnv(os.P_NOWAIT, program, args) support.wait_process(pid, exitcode=self.exitcode) @requires_os_func('spawnve') def test_spawnve_bytes(self): # Test bytes handling in parse_arglist and parse_envlist (#28114) - args = self.create_args(with_env=True, use_bytes=True) - exitcode = os.spawnve(os.P_WAIT, args[0], args, self.env) + program, args = self.create_args(with_env=True, use_bytes=True) + exitcode = os.spawnve(os.P_WAIT, program, args, self.env) self.assertEqual(exitcode, self.exitcode) @requires_os_func('spawnl') def test_spawnl_noargs(self): - args = self.create_args() - self.assertRaises(ValueError, os.spawnl, os.P_NOWAIT, args[0]) - self.assertRaises(ValueError, os.spawnl, os.P_NOWAIT, args[0], '') + program, __ = self.create_args() + self.assertRaises(ValueError, os.spawnl, os.P_NOWAIT, program) + self.assertRaises(ValueError, os.spawnl, os.P_NOWAIT, program, '') @requires_os_func('spawnle') def test_spawnle_noargs(self): - args = self.create_args() - self.assertRaises(ValueError, os.spawnle, os.P_NOWAIT, args[0], {}) - self.assertRaises(ValueError, os.spawnle, os.P_NOWAIT, args[0], '', {}) + program, __ = self.create_args() + self.assertRaises(ValueError, os.spawnle, os.P_NOWAIT, program, {}) + self.assertRaises(ValueError, os.spawnle, os.P_NOWAIT, program, '', {}) @requires_os_func('spawnv') def test_spawnv_noargs(self): - args = self.create_args() - self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], ()) - self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], []) - self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], ('',)) - self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], ['']) + program, __ = self.create_args() + self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, program, ()) + self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, program, []) + self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, program, ('',)) + self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, program, ['']) @requires_os_func('spawnve') def test_spawnve_noargs(self): - args = self.create_args() - self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], (), {}) - self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], [], {}) - self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], ('',), {}) - self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], [''], {}) + program, __ = self.create_args() + self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, program, (), {}) + self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, program, [], {}) + self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, program, ('',), {}) + self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, program, [''], {}) def _test_invalid_env(self, spawn): - args = [sys.executable, '-c', 'pass'] + program = sys.executable + args = self.quote_args([program, '-c', 'pass']) # null character in the environment variable name newenv = os.environ.copy() newenv["FRUIT\0VEGETABLE"] = "cabbage" try: - exitcode = spawn(os.P_WAIT, args[0], args, newenv) + exitcode = spawn(os.P_WAIT, program, args, newenv) except ValueError: pass else: @@ -3352,7 +3363,7 @@ def _test_invalid_env(self, spawn): newenv = os.environ.copy() newenv["FRUIT"] = "orange\0VEGETABLE=cabbage" try: - exitcode = spawn(os.P_WAIT, args[0], args, newenv) + exitcode = spawn(os.P_WAIT, program, args, newenv) except ValueError: pass else: @@ -3362,7 +3373,7 @@ def _test_invalid_env(self, spawn): newenv = os.environ.copy() newenv["FRUIT=ORANGE"] = "lemon" try: - exitcode = spawn(os.P_WAIT, args[0], args, newenv) + exitcode = spawn(os.P_WAIT, program, args, newenv) except ValueError: pass else: @@ -3375,10 +3386,11 @@ def _test_invalid_env(self, spawn): fp.write('import sys, os\n' 'if os.getenv("FRUIT") != "orange=lemon":\n' ' raise AssertionError') - args = [sys.executable, filename] + + args = self.quote_args([program, filename]) newenv = os.environ.copy() newenv["FRUIT"] = "orange=lemon" - exitcode = spawn(os.P_WAIT, args[0], args, newenv) + exitcode = spawn(os.P_WAIT, program, args, newenv) self.assertEqual(exitcode, 0) @requires_os_func('spawnve') diff --git a/Misc/NEWS.d/next/Tests/2022-11-06-18-42-38.gh-issue-75729.uGYJrv.rst b/Misc/NEWS.d/next/Tests/2022-11-06-18-42-38.gh-issue-75729.uGYJrv.rst new file mode 100644 index 000000000000..8baecdfc3188 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2022-11-06-18-42-38.gh-issue-75729.uGYJrv.rst @@ -0,0 +1,2 @@ +Fix the :func:`os.spawn* ` tests failing on Windows +when the working directory or interpreter path contains spaces. From webhook-mailer at python.org Sat Apr 8 03:56:28 2023 From: webhook-mailer at python.org (hugovk) Date: Sat, 08 Apr 2023 07:56:28 -0000 Subject: [Python-checkins] Docs: use Node.findall to avoid a deprecation warning (#99403) Message-ID: https://github.com/python/cpython/commit/1e9dfdacefa2c8c27762ba6491b0f570147ee355 commit: 1e9dfdacefa2c8c27762ba6491b0f570147ee355 branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: hugovk date: 2023-04-08T10:56:20+03:00 summary: Docs: use Node.findall to avoid a deprecation warning (#99403) files: M Doc/tools/extensions/c_annotations.py diff --git a/Doc/tools/extensions/c_annotations.py b/Doc/tools/extensions/c_annotations.py index 5af56433f415..3551bfa4c0f1 100644 --- a/Doc/tools/extensions/c_annotations.py +++ b/Doc/tools/extensions/c_annotations.py @@ -20,6 +20,7 @@ """ from os import path +import docutils from docutils import nodes from docutils.parsers.rst import directives from docutils.parsers.rst import Directive @@ -41,6 +42,16 @@ } +# Monkeypatch nodes.Node.findall for forwards compatability +# This patch can be dropped when the minimum Sphinx version is 4.4.0 +# or the minimum Docutils version is 0.18.1. +if docutils.__version_info__ < (0, 18, 1): + def findall(self, *args, **kwargs): + return iter(self.traverse(*args, **kwargs)) + + nodes.Node.findall = findall + + class RCEntry: def __init__(self, name): self.name = name @@ -87,7 +98,7 @@ def __init__(self, refcount_filename, stable_abi_file): self.stable_abi_data[name] = record def add_annotations(self, app, doctree): - for node in doctree.traverse(addnodes.desc_content): + for node in doctree.findall(addnodes.desc_content): par = node.parent if par['domain'] != 'c': continue From webhook-mailer at python.org Sat Apr 8 04:04:05 2023 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Apr 2023 08:04:05 -0000 Subject: [Python-checkins] gh-75729: Fix os.spawn tests not handling spaces on Windows (GH-99150) Message-ID: https://github.com/python/cpython/commit/b4f331820772c95c2d5eae9e5f416effb70a8db2 commit: b4f331820772c95c2d5eae9e5f416effb70a8db2 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-08T01:03:58-07:00 summary: gh-75729: Fix os.spawn tests not handling spaces on Windows (GH-99150) * Quote paths in os.spawn tests on Windows so they work with spaces * Add NEWS entry for os spawn test fix * Fix code style to avoid double negative in os.spawn tests Co-authored-by: Jelle Zijlstra --------- (cherry picked from commit a34c79623877a7ed0c86a6d48ddccffa0de76836) Co-authored-by: C.A.M. Gerlach Co-authored-by: Jelle Zijlstra files: A Misc/NEWS.d/next/Tests/2022-11-06-18-42-38.gh-issue-75729.uGYJrv.rst M Lib/test/test_os.py diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 58e83f658c44..aa414ca14889 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -3109,6 +3109,14 @@ def kill_process(pid): @support.requires_subprocess() class SpawnTests(unittest.TestCase): + @staticmethod + def quote_args(args): + # On Windows, os.spawn* simply joins arguments with spaces: + # arguments need to be quoted + if os.name != 'nt': + return args + return [f'"{arg}"' if " " in arg.strip() else arg for arg in args] + def create_args(self, *, with_env=False, use_bytes=False): self.exitcode = 17 @@ -3129,115 +3137,118 @@ def create_args(self, *, with_env=False, use_bytes=False): with open(filename, "w", encoding="utf-8") as fp: fp.write(code) - args = [sys.executable, filename] + program = sys.executable + args = self.quote_args([program, filename]) if use_bytes: + program = os.fsencode(program) args = [os.fsencode(a) for a in args] self.env = {os.fsencode(k): os.fsencode(v) for k, v in self.env.items()} - return args + return program, args @requires_os_func('spawnl') def test_spawnl(self): - args = self.create_args() - exitcode = os.spawnl(os.P_WAIT, args[0], *args) + program, args = self.create_args() + exitcode = os.spawnl(os.P_WAIT, program, *args) self.assertEqual(exitcode, self.exitcode) @requires_os_func('spawnle') def test_spawnle(self): - args = self.create_args(with_env=True) - exitcode = os.spawnle(os.P_WAIT, args[0], *args, self.env) + program, args = self.create_args(with_env=True) + exitcode = os.spawnle(os.P_WAIT, program, *args, self.env) self.assertEqual(exitcode, self.exitcode) @requires_os_func('spawnlp') def test_spawnlp(self): - args = self.create_args() - exitcode = os.spawnlp(os.P_WAIT, args[0], *args) + program, args = self.create_args() + exitcode = os.spawnlp(os.P_WAIT, program, *args) self.assertEqual(exitcode, self.exitcode) @requires_os_func('spawnlpe') def test_spawnlpe(self): - args = self.create_args(with_env=True) - exitcode = os.spawnlpe(os.P_WAIT, args[0], *args, self.env) + program, args = self.create_args(with_env=True) + exitcode = os.spawnlpe(os.P_WAIT, program, *args, self.env) self.assertEqual(exitcode, self.exitcode) @requires_os_func('spawnv') def test_spawnv(self): - args = self.create_args() - exitcode = os.spawnv(os.P_WAIT, args[0], args) + program, args = self.create_args() + exitcode = os.spawnv(os.P_WAIT, program, args) self.assertEqual(exitcode, self.exitcode) # Test for PyUnicode_FSConverter() - exitcode = os.spawnv(os.P_WAIT, FakePath(args[0]), args) + exitcode = os.spawnv(os.P_WAIT, FakePath(program), args) self.assertEqual(exitcode, self.exitcode) @requires_os_func('spawnve') def test_spawnve(self): - args = self.create_args(with_env=True) - exitcode = os.spawnve(os.P_WAIT, args[0], args, self.env) + program, args = self.create_args(with_env=True) + exitcode = os.spawnve(os.P_WAIT, program, args, self.env) self.assertEqual(exitcode, self.exitcode) @requires_os_func('spawnvp') def test_spawnvp(self): - args = self.create_args() - exitcode = os.spawnvp(os.P_WAIT, args[0], args) + program, args = self.create_args() + exitcode = os.spawnvp(os.P_WAIT, program, args) self.assertEqual(exitcode, self.exitcode) @requires_os_func('spawnvpe') def test_spawnvpe(self): - args = self.create_args(with_env=True) - exitcode = os.spawnvpe(os.P_WAIT, args[0], args, self.env) + program, args = self.create_args(with_env=True) + exitcode = os.spawnvpe(os.P_WAIT, program, args, self.env) self.assertEqual(exitcode, self.exitcode) @requires_os_func('spawnv') def test_nowait(self): - args = self.create_args() - pid = os.spawnv(os.P_NOWAIT, args[0], args) + program, args = self.create_args() + pid = os.spawnv(os.P_NOWAIT, program, args) support.wait_process(pid, exitcode=self.exitcode) @requires_os_func('spawnve') def test_spawnve_bytes(self): # Test bytes handling in parse_arglist and parse_envlist (#28114) - args = self.create_args(with_env=True, use_bytes=True) - exitcode = os.spawnve(os.P_WAIT, args[0], args, self.env) + program, args = self.create_args(with_env=True, use_bytes=True) + exitcode = os.spawnve(os.P_WAIT, program, args, self.env) self.assertEqual(exitcode, self.exitcode) @requires_os_func('spawnl') def test_spawnl_noargs(self): - args = self.create_args() - self.assertRaises(ValueError, os.spawnl, os.P_NOWAIT, args[0]) - self.assertRaises(ValueError, os.spawnl, os.P_NOWAIT, args[0], '') + program, __ = self.create_args() + self.assertRaises(ValueError, os.spawnl, os.P_NOWAIT, program) + self.assertRaises(ValueError, os.spawnl, os.P_NOWAIT, program, '') @requires_os_func('spawnle') def test_spawnle_noargs(self): - args = self.create_args() - self.assertRaises(ValueError, os.spawnle, os.P_NOWAIT, args[0], {}) - self.assertRaises(ValueError, os.spawnle, os.P_NOWAIT, args[0], '', {}) + program, __ = self.create_args() + self.assertRaises(ValueError, os.spawnle, os.P_NOWAIT, program, {}) + self.assertRaises(ValueError, os.spawnle, os.P_NOWAIT, program, '', {}) @requires_os_func('spawnv') def test_spawnv_noargs(self): - args = self.create_args() - self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], ()) - self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], []) - self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], ('',)) - self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], ['']) + program, __ = self.create_args() + self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, program, ()) + self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, program, []) + self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, program, ('',)) + self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, program, ['']) @requires_os_func('spawnve') def test_spawnve_noargs(self): - args = self.create_args() - self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], (), {}) - self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], [], {}) - self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], ('',), {}) - self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], [''], {}) + program, __ = self.create_args() + self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, program, (), {}) + self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, program, [], {}) + self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, program, ('',), {}) + self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, program, [''], {}) def _test_invalid_env(self, spawn): - args = [sys.executable, '-c', 'pass'] + program = sys.executable + args = self.quote_args([program, '-c', 'pass']) # null character in the environment variable name newenv = os.environ.copy() newenv["FRUIT\0VEGETABLE"] = "cabbage" try: - exitcode = spawn(os.P_WAIT, args[0], args, newenv) + exitcode = spawn(os.P_WAIT, program, args, newenv) except ValueError: pass else: @@ -3247,7 +3258,7 @@ def _test_invalid_env(self, spawn): newenv = os.environ.copy() newenv["FRUIT"] = "orange\0VEGETABLE=cabbage" try: - exitcode = spawn(os.P_WAIT, args[0], args, newenv) + exitcode = spawn(os.P_WAIT, program, args, newenv) except ValueError: pass else: @@ -3257,7 +3268,7 @@ def _test_invalid_env(self, spawn): newenv = os.environ.copy() newenv["FRUIT=ORANGE"] = "lemon" try: - exitcode = spawn(os.P_WAIT, args[0], args, newenv) + exitcode = spawn(os.P_WAIT, program, args, newenv) except ValueError: pass else: @@ -3270,10 +3281,11 @@ def _test_invalid_env(self, spawn): fp.write('import sys, os\n' 'if os.getenv("FRUIT") != "orange=lemon":\n' ' raise AssertionError') - args = [sys.executable, filename] + + args = self.quote_args([program, filename]) newenv = os.environ.copy() newenv["FRUIT"] = "orange=lemon" - exitcode = spawn(os.P_WAIT, args[0], args, newenv) + exitcode = spawn(os.P_WAIT, program, args, newenv) self.assertEqual(exitcode, 0) @requires_os_func('spawnve') diff --git a/Misc/NEWS.d/next/Tests/2022-11-06-18-42-38.gh-issue-75729.uGYJrv.rst b/Misc/NEWS.d/next/Tests/2022-11-06-18-42-38.gh-issue-75729.uGYJrv.rst new file mode 100644 index 000000000000..8baecdfc3188 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2022-11-06-18-42-38.gh-issue-75729.uGYJrv.rst @@ -0,0 +1,2 @@ +Fix the :func:`os.spawn* ` tests failing on Windows +when the working directory or interpreter path contains spaces. From webhook-mailer at python.org Sat Apr 8 04:24:35 2023 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Apr 2023 08:24:35 -0000 Subject: [Python-checkins] Docs: use Node.findall to avoid a deprecation warning (GH-99403) Message-ID: https://github.com/python/cpython/commit/31bec9198b194798e95c0c46bceff1913784d8ff commit: 31bec9198b194798e95c0c46bceff1913784d8ff branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-08T01:24:27-07:00 summary: Docs: use Node.findall to avoid a deprecation warning (GH-99403) (cherry picked from commit 1e9dfdacefa2c8c27762ba6491b0f570147ee355) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/tools/extensions/c_annotations.py diff --git a/Doc/tools/extensions/c_annotations.py b/Doc/tools/extensions/c_annotations.py index a845ef46c0ba..7cb6bd87103f 100644 --- a/Doc/tools/extensions/c_annotations.py +++ b/Doc/tools/extensions/c_annotations.py @@ -20,6 +20,7 @@ """ from os import path +import docutils from docutils import nodes from docutils.parsers.rst import directives from docutils.parsers.rst import Directive @@ -41,6 +42,16 @@ } +# Monkeypatch nodes.Node.findall for forwards compatability +# This patch can be dropped when the minimum Sphinx version is 4.4.0 +# or the minimum Docutils version is 0.18.1. +if docutils.__version_info__ < (0, 18, 1): + def findall(self, *args, **kwargs): + return iter(self.traverse(*args, **kwargs)) + + nodes.Node.findall = findall + + class RCEntry: def __init__(self, name): self.name = name @@ -87,7 +98,7 @@ def __init__(self, refcount_filename, stable_abi_file): self.stable_abi_data[name] = record def add_annotations(self, app, doctree): - for node in doctree.traverse(addnodes.desc_content): + for node in doctree.findall(addnodes.desc_content): par = node.parent if par['domain'] != 'c': continue From webhook-mailer at python.org Sat Apr 8 04:46:54 2023 From: webhook-mailer at python.org (hugovk) Date: Sat, 08 Apr 2023 08:46:54 -0000 Subject: [Python-checkins] gh-100574: add examples/links to the `strptime`/`strftime` docs (#100575) Message-ID: https://github.com/python/cpython/commit/3310b94d3db2f477cf2b8789c30ac0f22f82d2dd commit: 3310b94d3db2f477cf2b8789c30ac0f22f82d2dd branch: main author: Ezio Melotti committer: hugovk date: 2023-04-08T11:46:47+03:00 summary: gh-100574: add examples/links to the `strptime`/`strftime` docs (#100575) files: M Doc/library/datetime.rst diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index 50827b27ebea..761f5f04b9b2 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -737,18 +737,16 @@ Instance methods: .. method:: date.strftime(format) Return a string representing the date, controlled by an explicit format string. - Format codes referring to hours, minutes or seconds will see 0 values. For a - complete list of formatting directives, see - :ref:`strftime-strptime-behavior`. + Format codes referring to hours, minutes or seconds will see 0 values. + See also :ref:`strftime-strptime-behavior` and :meth:`date.isoformat`. .. method:: date.__format__(format) Same as :meth:`.date.strftime`. This makes it possible to specify a format string for a :class:`.date` object in :ref:`formatted string - literals ` and when using :meth:`str.format`. For a - complete list of formatting directives, see - :ref:`strftime-strptime-behavior`. + literals ` and when using :meth:`str.format`. + See also :ref:`strftime-strptime-behavior` and :meth:`date.isoformat`. Examples of Usage: :class:`date` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1051,8 +1049,8 @@ Other constructors, all class methods: :exc:`ValueError` is raised if the date_string and format can't be parsed by :func:`time.strptime` or if it returns a value which isn't a - time tuple. For a complete list of formatting directives, see - :ref:`strftime-strptime-behavior`. + time tuple. See also :ref:`strftime-strptime-behavior` and + :meth:`datetime.fromisoformat`. @@ -1510,20 +1508,21 @@ Instance methods: (which :func:`time.ctime` invokes, but which :meth:`datetime.ctime` does not invoke) conforms to the C standard. + .. method:: datetime.strftime(format) - Return a string representing the date and time, controlled by an explicit format - string. For a complete list of formatting directives, see - :ref:`strftime-strptime-behavior`. + Return a string representing the date and time, + controlled by an explicit format string. + See also :ref:`strftime-strptime-behavior` and :meth:`datetime.isoformat`. .. method:: datetime.__format__(format) Same as :meth:`.datetime.strftime`. This makes it possible to specify a format string for a :class:`.datetime` object in :ref:`formatted string - literals ` and when using :meth:`str.format`. For a - complete list of formatting directives, see - :ref:`strftime-strptime-behavior`. + literals ` and when using :meth:`str.format`. + See also :ref:`strftime-strptime-behavior` and :meth:`datetime.isoformat`. + Examples of Usage: :class:`.datetime` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1868,17 +1867,15 @@ Instance methods: .. method:: time.strftime(format) Return a string representing the time, controlled by an explicit format - string. For a complete list of formatting directives, see - :ref:`strftime-strptime-behavior`. + string. See also :ref:`strftime-strptime-behavior` and :meth:`time.isoformat`. .. method:: time.__format__(format) - Same as :meth:`.time.strftime`. This makes it possible to specify a format string - for a :class:`.time` object in :ref:`formatted string - literals ` and when using :meth:`str.format`. For a - complete list of formatting directives, see - :ref:`strftime-strptime-behavior`. + Same as :meth:`.time.strftime`. This makes it possible to specify + a format string for a :class:`.time` object in :ref:`formatted string + literals ` and when using :meth:`str.format`. + See also :ref:`strftime-strptime-behavior` and :meth:`time.isoformat`. .. method:: time.utcoffset() @@ -2320,6 +2317,14 @@ versus :meth:`strptime`: :meth:`strftime` and :meth:`strptime` Format Codes ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +These methods accept format codes that can be used to parse and format dates:: + + >>> datetime.strptime('31/01/22 23:59:59.999999', + ... '%d/%m/%y %H:%M:%S.%f') + datetime.datetime(2022, 1, 31, 23, 59, 59, 999999) + >>> _.strftime('%a %d %b %Y, %I:%M%p') + 'Mon 31 Jan 2022, 11:59PM' + The following is a list of all the format codes that the 1989 C standard requires, and these work on all platforms with a standard C implementation. From webhook-mailer at python.org Sat Apr 8 04:56:38 2023 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Apr 2023 08:56:38 -0000 Subject: [Python-checkins] gh-100574: add examples/links to the `strptime`/`strftime` docs (GH-100575) Message-ID: https://github.com/python/cpython/commit/7b03d0f7c51301286399c71be020980e8c615a23 commit: 7b03d0f7c51301286399c71be020980e8c615a23 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-08T01:56:31-07:00 summary: gh-100574: add examples/links to the `strptime`/`strftime` docs (GH-100575) (cherry picked from commit 3310b94d3db2f477cf2b8789c30ac0f22f82d2dd) Co-authored-by: Ezio Melotti files: M Doc/library/datetime.rst diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index 443d80cf006b..d46eaade142e 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -737,18 +737,16 @@ Instance methods: .. method:: date.strftime(format) Return a string representing the date, controlled by an explicit format string. - Format codes referring to hours, minutes or seconds will see 0 values. For a - complete list of formatting directives, see - :ref:`strftime-strptime-behavior`. + Format codes referring to hours, minutes or seconds will see 0 values. + See also :ref:`strftime-strptime-behavior` and :meth:`date.isoformat`. .. method:: date.__format__(format) Same as :meth:`.date.strftime`. This makes it possible to specify a format string for a :class:`.date` object in :ref:`formatted string - literals ` and when using :meth:`str.format`. For a - complete list of formatting directives, see - :ref:`strftime-strptime-behavior`. + literals ` and when using :meth:`str.format`. + See also :ref:`strftime-strptime-behavior` and :meth:`date.isoformat`. Examples of Usage: :class:`date` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1051,8 +1049,8 @@ Other constructors, all class methods: :exc:`ValueError` is raised if the date_string and format can't be parsed by :func:`time.strptime` or if it returns a value which isn't a - time tuple. For a complete list of formatting directives, see - :ref:`strftime-strptime-behavior`. + time tuple. See also :ref:`strftime-strptime-behavior` and + :meth:`datetime.fromisoformat`. @@ -1510,20 +1508,21 @@ Instance methods: (which :func:`time.ctime` invokes, but which :meth:`datetime.ctime` does not invoke) conforms to the C standard. + .. method:: datetime.strftime(format) - Return a string representing the date and time, controlled by an explicit format - string. For a complete list of formatting directives, see - :ref:`strftime-strptime-behavior`. + Return a string representing the date and time, + controlled by an explicit format string. + See also :ref:`strftime-strptime-behavior` and :meth:`datetime.isoformat`. .. method:: datetime.__format__(format) Same as :meth:`.datetime.strftime`. This makes it possible to specify a format string for a :class:`.datetime` object in :ref:`formatted string - literals ` and when using :meth:`str.format`. For a - complete list of formatting directives, see - :ref:`strftime-strptime-behavior`. + literals ` and when using :meth:`str.format`. + See also :ref:`strftime-strptime-behavior` and :meth:`datetime.isoformat`. + Examples of Usage: :class:`.datetime` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1868,17 +1867,15 @@ Instance methods: .. method:: time.strftime(format) Return a string representing the time, controlled by an explicit format - string. For a complete list of formatting directives, see - :ref:`strftime-strptime-behavior`. + string. See also :ref:`strftime-strptime-behavior` and :meth:`time.isoformat`. .. method:: time.__format__(format) - Same as :meth:`.time.strftime`. This makes it possible to specify a format string - for a :class:`.time` object in :ref:`formatted string - literals ` and when using :meth:`str.format`. For a - complete list of formatting directives, see - :ref:`strftime-strptime-behavior`. + Same as :meth:`.time.strftime`. This makes it possible to specify + a format string for a :class:`.time` object in :ref:`formatted string + literals ` and when using :meth:`str.format`. + See also :ref:`strftime-strptime-behavior` and :meth:`time.isoformat`. .. method:: time.utcoffset() @@ -2320,6 +2317,14 @@ versus :meth:`strptime`: :meth:`strftime` and :meth:`strptime` Format Codes ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +These methods accept format codes that can be used to parse and format dates:: + + >>> datetime.strptime('31/01/22 23:59:59.999999', + ... '%d/%m/%y %H:%M:%S.%f') + datetime.datetime(2022, 1, 31, 23, 59, 59, 999999) + >>> _.strftime('%a %d %b %Y, %I:%M%p') + 'Mon 31 Jan 2022, 11:59PM' + The following is a list of all the format codes that the 1989 C standard requires, and these work on all platforms with a standard C implementation. From webhook-mailer at python.org Sat Apr 8 05:04:54 2023 From: webhook-mailer at python.org (hugovk) Date: Sat, 08 Apr 2023 09:04:54 -0000 Subject: [Python-checkins] gh-100176: Tools/iobench: Remove redundant compat code for Python <= 3.2 (#100197) Message-ID: https://github.com/python/cpython/commit/b22d021ee6309f9b0d43e683056db84cfb6fd3c0 commit: b22d021ee6309f9b0d43e683056db84cfb6fd3c0 branch: main author: Hugo van Kemenade committer: hugovk date: 2023-04-08T12:04:47+03:00 summary: gh-100176: Tools/iobench: Remove redundant compat code for Python <= 3.2 (#100197) Co-authored-by: Alex Waygood files: M Tools/iobench/iobench.py diff --git a/Tools/iobench/iobench.py b/Tools/iobench/iobench.py index b0a7feb92e4f..4017149ec916 100644 --- a/Tools/iobench/iobench.py +++ b/Tools/iobench/iobench.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -# This file should be kept compatible with both Python 2.6 and Python >= 3.0. - import itertools import os import platform @@ -14,39 +11,37 @@ TEXT_ENCODING = 'utf8' NEWLINES = 'lf' -# Compatibility -try: - xrange -except NameError: - xrange = range def text_open(fn, mode, encoding=None): try: return open(fn, mode, encoding=encoding or TEXT_ENCODING) except TypeError: - if 'r' in mode: - mode += 'U' # 'U' mode is needed only in Python 2.x return open(fn, mode) + def get_file_sizes(): for s in ['20 KiB', '400 KiB', '10 MiB']: size, unit = s.split() size = int(size) * {'KiB': 1024, 'MiB': 1024 ** 2}[unit] yield s.replace(' ', ''), size + def get_binary_files(): return ((name + ".bin", size) for name, size in get_file_sizes()) + def get_text_files(): - return (("%s-%s-%s.txt" % (name, TEXT_ENCODING, NEWLINES), size) + return ((f"{name}-{TEXT_ENCODING}-{NEWLINES}.txt", size) for name, size in get_file_sizes()) + def with_open_mode(mode): def decorate(f): f.file_open_mode = mode return f return decorate + def with_sizes(*sizes): def decorate(f): f.file_sizes = sizes @@ -64,6 +59,7 @@ def read_bytewise(f): while f.read(1): pass + @with_open_mode("r") @with_sizes("medium") def read_small_chunks(f): @@ -72,6 +68,7 @@ def read_small_chunks(f): while f.read(20): pass + @with_open_mode("r") @with_sizes("medium") def read_big_chunks(f): @@ -80,6 +77,7 @@ def read_big_chunks(f): while f.read(4096): pass + @with_open_mode("r") @with_sizes("small", "medium", "large") def read_whole_file(f): @@ -88,6 +86,7 @@ def read_whole_file(f): while f.read(): pass + @with_open_mode("rt") @with_sizes("medium") def read_lines(f): @@ -96,6 +95,7 @@ def read_lines(f): for line in f: pass + @with_open_mode("r") @with_sizes("medium") def seek_forward_bytewise(f): @@ -103,9 +103,10 @@ def seek_forward_bytewise(f): f.seek(0, 2) size = f.tell() f.seek(0, 0) - for i in xrange(0, size - 1): + for i in range(0, size - 1): f.seek(i, 0) + @with_open_mode("r") @with_sizes("medium") def seek_forward_blockwise(f): @@ -113,9 +114,10 @@ def seek_forward_blockwise(f): f.seek(0, 2) size = f.tell() f.seek(0, 0) - for i in xrange(0, size - 1, 1000): + for i in range(0, size - 1, 1000): f.seek(i, 0) + @with_open_mode("rb") @with_sizes("medium") def read_seek_bytewise(f): @@ -124,6 +126,7 @@ def read_seek_bytewise(f): while f.read(1): f.seek(1, 1) + @with_open_mode("rb") @with_sizes("medium") def read_seek_blockwise(f): @@ -137,28 +140,31 @@ def read_seek_blockwise(f): @with_sizes("small") def write_bytewise(f, source): """ write one unit at a time """ - for i in xrange(0, len(source)): + for i in range(0, len(source)): f.write(source[i:i+1]) + @with_open_mode("w") @with_sizes("medium") def write_small_chunks(f, source): """ write 20 units at a time """ - for i in xrange(0, len(source), 20): + for i in range(0, len(source), 20): f.write(source[i:i+20]) + @with_open_mode("w") @with_sizes("medium") def write_medium_chunks(f, source): """ write 4096 units at a time """ - for i in xrange(0, len(source), 4096): + for i in range(0, len(source), 4096): f.write(source[i:i+4096]) + @with_open_mode("w") @with_sizes("large") def write_large_chunks(f, source): """ write 1e6 units at a time """ - for i in xrange(0, len(source), 1000000): + for i in range(0, len(source), 1000000): f.write(source[i:i+1000000]) @@ -167,59 +173,65 @@ def write_large_chunks(f, source): def modify_bytewise(f, source): """ modify one unit at a time """ f.seek(0) - for i in xrange(0, len(source)): + for i in range(0, len(source)): f.write(source[i:i+1]) + @with_open_mode("w+") @with_sizes("medium") def modify_small_chunks(f, source): """ modify 20 units at a time """ f.seek(0) - for i in xrange(0, len(source), 20): + for i in range(0, len(source), 20): f.write(source[i:i+20]) + @with_open_mode("w+") @with_sizes("medium") def modify_medium_chunks(f, source): """ modify 4096 units at a time """ f.seek(0) - for i in xrange(0, len(source), 4096): + for i in range(0, len(source), 4096): f.write(source[i:i+4096]) + @with_open_mode("wb+") @with_sizes("medium") def modify_seek_forward_bytewise(f, source): """ alternate write & seek one unit """ f.seek(0) - for i in xrange(0, len(source), 2): + for i in range(0, len(source), 2): f.write(source[i:i+1]) f.seek(i+2) + @with_open_mode("wb+") @with_sizes("medium") def modify_seek_forward_blockwise(f, source): """ alternate write & seek 1000 units """ f.seek(0) - for i in xrange(0, len(source), 2000): + for i in range(0, len(source), 2000): f.write(source[i:i+1000]) f.seek(i+2000) + # XXX the 2 following tests don't work with py3k's text IO @with_open_mode("wb+") @with_sizes("medium") def read_modify_bytewise(f, source): """ alternate read & write one unit """ f.seek(0) - for i in xrange(0, len(source), 2): + for i in range(0, len(source), 2): f.read(1) f.write(source[i+1:i+2]) + @with_open_mode("wb+") @with_sizes("medium") def read_modify_blockwise(f, source): """ alternate read & write 1000 units """ f.seek(0) - for i in xrange(0, len(source), 2000): + for i in range(0, len(source), 2000): f.read(1000) f.write(source[i+1000:i+2000]) @@ -242,6 +254,7 @@ def read_modify_blockwise(f, source): read_modify_bytewise, read_modify_blockwise, ] + def run_during(duration, func): _t = time.time n = 0 @@ -257,6 +270,7 @@ def run_during(duration, func): real = (end[4] if start[4] else time.time()) - real_start return n, real, sum(end[0:2]) - sum(start[0:2]) + def warm_cache(filename): with open(filename, "rb") as f: f.read() @@ -266,9 +280,7 @@ def run_all_tests(options): def print_label(filename, func): name = re.split(r'[-.]', filename)[0] out.write( - ("[%s] %s... " - % (name.center(7), func.__doc__.strip()) - ).ljust(52)) + f"[{name.center(7)}] {func.__doc__.strip()}... ".ljust(52)) out.flush() def print_results(size, n, real, cpu): @@ -276,8 +288,9 @@ def print_results(size, n, real, cpu): bw = ("%4d MiB/s" if bw > 100 else "%.3g MiB/s") % bw out.write(bw.rjust(12) + "\n") if cpu < 0.90 * real: - out.write(" warning: test above used only %d%% CPU, " - "result may be flawed!\n" % (100.0 * cpu / real)) + out.write(" warning: test above used only " + f"{cpu / real:%} CPU, " + "result may be flawed!\n") def run_one_test(name, size, open_func, test_func, *args): mode = test_func.file_open_mode @@ -308,22 +321,15 @@ def run_test_family(tests, mode_filter, files, open_func, *make_args): "large": 2, } - print("Python %s" % sys.version) - if sys.version_info < (3, 3): - if sys.maxunicode > 0xffff: - text = "UCS-4 (wide build)" - else: - text = "UTF-16 (narrow build)" - else: - text = "PEP 393" - print("Unicode: %s" % text) + print(f"Python {sys.version}") + print("Unicode: PEP 393") print(platform.platform()) binary_files = list(get_binary_files()) text_files = list(get_text_files()) if "b" in options: print("Binary unit = one byte") if "t" in options: - print("Text unit = one character (%s-decoded)" % TEXT_ENCODING) + print(f"Text unit = one character ({TEXT_ENCODING}-decoded)") # Binary reads if "b" in options and "r" in options: @@ -338,6 +344,7 @@ def run_test_family(tests, mode_filter, files, open_func, *make_args): # Binary writes if "b" in options and "w" in options: print("\n** Binary append **\n") + def make_test_source(name, size): with open(name, "rb") as f: return f.read() @@ -347,6 +354,7 @@ def make_test_source(name, size): # Text writes if "t" in options and "w" in options: print("\n** Text append **\n") + def make_test_source(name, size): with text_open(name, "r") as f: return f.read() @@ -356,6 +364,7 @@ def make_test_source(name, size): # Binary overwrites if "b" in options and "w" in options: print("\n** Binary overwrite **\n") + def make_test_source(name, size): with open(name, "rb") as f: return f.read() @@ -365,6 +374,7 @@ def make_test_source(name, size): # Text overwrites if "t" in options and "w" in options: print("\n** Text overwrite **\n") + def make_test_source(name, size): with text_open(name, "r") as f: return f.read() @@ -388,7 +398,7 @@ def prepare_files(): break else: raise RuntimeError( - "Couldn't find chunk marker in %s !" % __file__) + f"Couldn't find chunk marker in {__file__} !") if NEWLINES == "all": it = itertools.cycle(["\n", "\r", "\r\n"]) else: @@ -414,6 +424,7 @@ def prepare_files(): f.write(head) f.write(tail) + def main(): global TEXT_ENCODING, NEWLINES @@ -433,7 +444,7 @@ def main(): help="run write & modify tests") parser.add_option("-E", "--encoding", action="store", dest="encoding", default=None, - help="encoding for text tests (default: %s)" % TEXT_ENCODING) + help=f"encoding for text tests (default: {TEXT_ENCODING})") parser.add_option("-N", "--newlines", action="store", dest="newlines", default='lf', help="line endings for text tests " @@ -446,7 +457,7 @@ def main(): parser.error("unexpected arguments") NEWLINES = options.newlines.lower() if NEWLINES not in ('lf', 'cr', 'crlf', 'all'): - parser.error("invalid 'newlines' option: %r" % NEWLINES) + parser.error(f"invalid 'newlines' option: {NEWLINES!r}") test_options = "" if options.read: @@ -471,6 +482,7 @@ def main(): prepare_files() run_all_tests(test_options) + if __name__ == "__main__": main() From webhook-mailer at python.org Sat Apr 8 10:09:07 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sat, 08 Apr 2023 14:09:07 -0000 Subject: [Python-checkins] gh-103373: Improve documentation for `__mro_entries__` (#103374) Message-ID: https://github.com/python/cpython/commit/0ba0ca05d2b56afa0b055db02233e703fe138918 commit: 0ba0ca05d2b56afa0b055db02233e703fe138918 branch: main author: Alex Waygood committer: AlexWaygood date: 2023-04-08T15:09:00+01:00 summary: gh-103373: Improve documentation for `__mro_entries__` (#103374) files: M Doc/reference/datamodel.rst diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index a09d5529c8c6..ed9ebaba784b 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -2086,11 +2086,15 @@ When a class definition is executed, the following steps occur: Resolving MRO entries ^^^^^^^^^^^^^^^^^^^^^ -If a base that appears in class definition is not an instance of :class:`type`, -then an ``__mro_entries__`` method is searched on it. If found, it is called -with the original bases tuple. This method must return a tuple of classes that -will be used instead of this base. The tuple may be empty, in such case -the original base is ignored. +.. method:: object.__mro_entries__(self, bases) + + If a base that appears in a class definition is not an instance of + :class:`type`, then an ``__mro_entries__`` method is searched on the base. + If an ``__mro_entries__`` method is found, the base is substituted with the + result of a call to ``__mro_entries__`` when creating the class. + The method is called with the original bases tuple, and must return a tuple + of classes that will be used instead of the base. The returned tuple may be + empty: in these cases, the original base is ignored. .. seealso:: From webhook-mailer at python.org Sat Apr 8 10:16:50 2023 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Apr 2023 14:16:50 -0000 Subject: [Python-checkins] gh-103373: Improve documentation for `__mro_entries__` (GH-103374) Message-ID: https://github.com/python/cpython/commit/77359a86b8b48991eb1b411be1b84662343c8fe3 commit: 77359a86b8b48991eb1b411be1b84662343c8fe3 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-08T07:16:43-07:00 summary: gh-103373: Improve documentation for `__mro_entries__` (GH-103374) (cherry picked from commit 0ba0ca05d2b56afa0b055db02233e703fe138918) Co-authored-by: Alex Waygood files: M Doc/reference/datamodel.rst diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 87c538f6f2c1..b086be26999c 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -2085,11 +2085,15 @@ When a class definition is executed, the following steps occur: Resolving MRO entries ^^^^^^^^^^^^^^^^^^^^^ -If a base that appears in class definition is not an instance of :class:`type`, -then an ``__mro_entries__`` method is searched on it. If found, it is called -with the original bases tuple. This method must return a tuple of classes that -will be used instead of this base. The tuple may be empty, in such case -the original base is ignored. +.. method:: object.__mro_entries__(self, bases) + + If a base that appears in a class definition is not an instance of + :class:`type`, then an ``__mro_entries__`` method is searched on the base. + If an ``__mro_entries__`` method is found, the base is substituted with the + result of a call to ``__mro_entries__`` when creating the class. + The method is called with the original bases tuple, and must return a tuple + of classes that will be used instead of the base. The returned tuple may be + empty: in these cases, the original base is ignored. .. seealso:: From webhook-mailer at python.org Sat Apr 8 13:56:49 2023 From: webhook-mailer at python.org (gpshead) Date: Sat, 08 Apr 2023 17:56:49 -0000 Subject: [Python-checkins] gh-103242: Migrate SSLContext.set_ecdh_curve not to use deprecated APIs (#103378) Message-ID: https://github.com/python/cpython/commit/35167043e3a21055a94cf3de6ceccd1585554cb8 commit: 35167043e3a21055a94cf3de6ceccd1585554cb8 branch: main author: Dong-hee Na committer: gpshead date: 2023-04-08T10:56:42-07:00 summary: gh-103242: Migrate SSLContext.set_ecdh_curve not to use deprecated APIs (#103378) Migrate `SSLContext.set_ecdh_curve()` not to use deprecated OpenSSL APIs. files: A Misc/NEWS.d/next/Core and Builtins/2023-04-08-17-13-07.gh-issue-103242.ysI1b3.rst M Modules/_ssl.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-08-17-13-07.gh-issue-103242.ysI1b3.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-08-17-13-07.gh-issue-103242.ysI1b3.rst new file mode 100644 index 000000000000..38b107f3be17 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-08-17-13-07.gh-issue-103242.ysI1b3.rst @@ -0,0 +1,2 @@ +Migrate :meth:`~ssl.SSLContext.set_ecdh_curve` method not to use deprecated +OpenSSL APIs. Patch by Dong-hee Na. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 5f17cd502d45..c9e2f24d66cc 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -4336,8 +4336,6 @@ _ssl__SSLContext_set_ecdh_curve(PySSLContext *self, PyObject *name) { PyObject *name_bytes; int nid; - EC_KEY *key; - if (!PyUnicode_FSConverter(name, &name_bytes)) return NULL; assert(PyBytes_Check(name_bytes)); @@ -4348,13 +4346,20 @@ _ssl__SSLContext_set_ecdh_curve(PySSLContext *self, PyObject *name) "unknown elliptic curve name %R", name); return NULL; } - key = EC_KEY_new_by_curve_name(nid); +#if OPENSSL_VERSION_MAJOR < 3 + EC_KEY *key = EC_KEY_new_by_curve_name(nid); if (key == NULL) { _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); return NULL; } SSL_CTX_set_tmp_ecdh(self->ctx, key); EC_KEY_free(key); +#else + if (!SSL_CTX_set1_groups(self->ctx, &nid, 1)) { + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); + return NULL; + } +#endif Py_RETURN_NONE; } From webhook-mailer at python.org Sat Apr 8 14:21:34 2023 From: webhook-mailer at python.org (miss-islington) Date: Sat, 08 Apr 2023 18:21:34 -0000 Subject: [Python-checkins] gh-103242: Migrate SSLContext.set_ecdh_curve not to use deprecated APIs (GH-103378) Message-ID: https://github.com/python/cpython/commit/4fa5fda14b11457dda7ef389e5486bfe3ea7b8f5 commit: 4fa5fda14b11457dda7ef389e5486bfe3ea7b8f5 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-08T11:21:27-07:00 summary: gh-103242: Migrate SSLContext.set_ecdh_curve not to use deprecated APIs (GH-103378) Migrate `SSLContext.set_ecdh_curve()` not to use deprecated OpenSSL APIs. (cherry picked from commit 35167043e3a21055a94cf3de6ceccd1585554cb8) Co-authored-by: Dong-hee Na files: A Misc/NEWS.d/next/Core and Builtins/2023-04-08-17-13-07.gh-issue-103242.ysI1b3.rst M Modules/_ssl.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-08-17-13-07.gh-issue-103242.ysI1b3.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-08-17-13-07.gh-issue-103242.ysI1b3.rst new file mode 100644 index 000000000000..38b107f3be17 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-08-17-13-07.gh-issue-103242.ysI1b3.rst @@ -0,0 +1,2 @@ +Migrate :meth:`~ssl.SSLContext.set_ecdh_curve` method not to use deprecated +OpenSSL APIs. Patch by Dong-hee Na. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 61490783e9ba..1a4102434ede 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -4355,8 +4355,6 @@ _ssl__SSLContext_set_ecdh_curve(PySSLContext *self, PyObject *name) { PyObject *name_bytes; int nid; - EC_KEY *key; - if (!PyUnicode_FSConverter(name, &name_bytes)) return NULL; assert(PyBytes_Check(name_bytes)); @@ -4367,13 +4365,20 @@ _ssl__SSLContext_set_ecdh_curve(PySSLContext *self, PyObject *name) "unknown elliptic curve name %R", name); return NULL; } - key = EC_KEY_new_by_curve_name(nid); +#if OPENSSL_VERSION_MAJOR < 3 + EC_KEY *key = EC_KEY_new_by_curve_name(nid); if (key == NULL) { _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); return NULL; } SSL_CTX_set_tmp_ecdh(self->ctx, key); EC_KEY_free(key); +#else + if (!SSL_CTX_set1_groups(self->ctx, &nid, 1)) { + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); + return NULL; + } +#endif Py_RETURN_NONE; } From webhook-mailer at python.org Sat Apr 8 21:04:00 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sun, 09 Apr 2023 01:04:00 -0000 Subject: [Python-checkins] gh-103092: Isolate `socket` module (#103094) Message-ID: https://github.com/python/cpython/commit/f329a8bc1e57e454852f8887df6267b42047cd1b commit: f329a8bc1e57e454852f8887df6267b42047cd1b branch: main author: Erlend E. Aasland committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-04-09T06:33:52+05:30 summary: gh-103092: Isolate `socket` module (#103094) files: A Misc/NEWS.d/next/Library/2023-04-03-23-43-12.gh-issue-103092.3xqk4y.rst M Lib/test/test_socket.py M Modules/socketmodule.c M Modules/socketmodule.h M Tools/c-analyzer/cpython/globals-to-fix.tsv diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 32252f7b741f..bb7bf436d2d7 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -8,6 +8,7 @@ import array import contextlib import errno +import gc import io import itertools import math @@ -836,6 +837,12 @@ def requireSocket(*args): class GeneralModuleTests(unittest.TestCase): + @unittest.skipUnless(_socket is not None, 'need _socket module') + def test_socket_type(self): + self.assertTrue(gc.is_tracked(_socket.socket)) + with self.assertRaisesRegex(TypeError, "immutable"): + _socket.socket.foo = 1 + def test_SocketType_is_socketobject(self): import _socket self.assertTrue(socket.SocketType is _socket.socket) diff --git a/Misc/NEWS.d/next/Library/2023-04-03-23-43-12.gh-issue-103092.3xqk4y.rst b/Misc/NEWS.d/next/Library/2023-04-03-23-43-12.gh-issue-103092.3xqk4y.rst new file mode 100644 index 000000000000..e7586a223c14 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-03-23-43-12.gh-issue-103092.3xqk4y.rst @@ -0,0 +1 @@ +Isolate :mod:`!_socket` (apply :pep:`687`). Patch by Erlend E. Aasland. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 49342b3d48de..656cd546d46d 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -108,6 +108,7 @@ Local naming conventions: #define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_fileutils.h" // _Py_set_inheritable() +#include "pycore_moduleobject.h" // _PyModule_GetState #include "structmember.h" // PyMemberDef #ifdef _Py_MEMORY_SANITIZER @@ -337,9 +338,9 @@ static FlagRuntimeInfo win_runtime_flags[] = { /*[clinic input] module _socket -class _socket.socket "PySocketSockObject *" "&sock_type" +class _socket.socket "PySocketSockObject *" "clinic_state()->sock_type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=7a8313d9b7f51988]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=2db2489bd2219fd8]*/ static int remove_unusable_flags(PyObject *m) @@ -541,22 +542,59 @@ remove_unusable_flags(PyObject *m) #define INADDR_NONE (-1) #endif +typedef struct _socket_state { + /* The sock_type variable contains pointers to various functions, + some of which call new_sockobject(), which uses sock_type, so + there has to be a circular reference. */ + PyTypeObject *sock_type; + + /* Global variable holding the exception type for errors detected + by this module (but not argument type or memory errors, etc.). */ + PyObject *socket_herror; + PyObject *socket_gaierror; + + /* Default timeout for new sockets */ + _PyTime_t defaulttimeout; + +#if defined(HAVE_ACCEPT) || defined(HAVE_ACCEPT4) +#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) + /* accept4() is available on Linux 2.6.28+ and glibc 2.10 */ + int accept4_works; +#endif +#endif + +#ifdef SOCK_CLOEXEC + /* socket() and socketpair() fail with EINVAL on Linux kernel older + * than 2.6.27 if SOCK_CLOEXEC flag is set in the socket type. */ + int sock_cloexec_works; +#endif +} socket_state; + +static inline socket_state * +get_module_state(PyObject *mod) +{ + void *state = _PyModule_GetState(mod); + assert(state != NULL); + return (socket_state *)state; +} + +static struct PyModuleDef socketmodule; + +static inline socket_state * +find_module_state_by_def(PyTypeObject *type) +{ + PyObject *mod = PyType_GetModuleByDef(type, &socketmodule); + assert(mod != NULL); + return get_module_state(mod); +} + +#define clinic_state() (find_module_state_by_def(type)) #include "clinic/socketmodule.c.h" +#undef clinic_state /* XXX There's a problem here: *static* functions are not supposed to have a Py prefix (or use CapitalizedWords). Later... */ -/* Global variable holding the exception type for errors detected - by this module (but not argument type or memory errors, etc.). */ -static PyObject *socket_herror; -static PyObject *socket_gaierror; - -/* A forward reference to the socket type object. - The sock_type variable contains pointers to various functions, - some of which call new_sockobject(), which uses sock_type, so - there has to be a circular reference. */ -static PyTypeObject sock_type; - #if defined(HAVE_POLL_H) #include #elif defined(HAVE_SYS_POLL_H) @@ -641,7 +679,7 @@ set_error(void) #if defined(HAVE_GETHOSTBYNAME_R) || defined (HAVE_GETHOSTBYNAME) || defined (HAVE_GETHOSTBYADDR) static PyObject * -set_herror(int h_error) +set_herror(socket_state *state, int h_error) { PyObject *v; @@ -651,7 +689,7 @@ set_herror(int h_error) v = Py_BuildValue("(is)", h_error, "host not found"); #endif if (v != NULL) { - PyErr_SetObject(socket_herror, v); + PyErr_SetObject(state->socket_herror, v); Py_DECREF(v); } @@ -662,7 +700,7 @@ set_herror(int h_error) #ifdef HAVE_GETADDRINFO static PyObject * -set_gaierror(int error) +set_gaierror(socket_state *state, int error) { PyObject *v; @@ -678,7 +716,7 @@ set_gaierror(int error) v = Py_BuildValue("(is)", error, "getaddrinfo failed"); #endif if (v != NULL) { - PyErr_SetObject(socket_gaierror, v); + PyErr_SetObject(state->socket_gaierror, v); Py_DECREF(v); } @@ -991,11 +1029,8 @@ sock_call(PySocketSockObject *s, /* Initialize a new socket object. */ -/* Default timeout for new sockets */ -static _PyTime_t defaulttimeout = _PYTIME_FROMSECONDS(-1); - static int -init_sockobject(PySocketSockObject *s, +init_sockobject(socket_state *state, PySocketSockObject *s, SOCKET_T fd, int family, int type, int proto) { s->sock_fd = fd; @@ -1025,13 +1060,14 @@ init_sockobject(PySocketSockObject *s, else #endif { - s->sock_timeout = defaulttimeout; - if (defaulttimeout >= 0) { + s->sock_timeout = state->defaulttimeout; + if (state->defaulttimeout >= 0) { if (internal_setblocking(s, 0) == -1) { return -1; } } } + s->state = state; return 0; } @@ -1043,14 +1079,15 @@ init_sockobject(PySocketSockObject *s, in NEWOBJ()). */ static PySocketSockObject * -new_sockobject(SOCKET_T fd, int family, int type, int proto) +new_sockobject(socket_state *state, SOCKET_T fd, int family, int type, + int proto) { - PySocketSockObject *s; - s = (PySocketSockObject *) - PyType_GenericNew(&sock_type, NULL, NULL); - if (s == NULL) + PyTypeObject *tp = state->sock_type; + PySocketSockObject *s = (PySocketSockObject *)tp->tp_alloc(tp, 0); + if (s == NULL) { return NULL; - if (init_sockobject(s, fd, family, type, proto) == -1) { + } + if (init_sockobject(state, s, fd, family, type, proto) == -1) { Py_DECREF(s); return NULL; } @@ -1074,7 +1111,8 @@ static PyThread_type_lock netdb_lock; an error occurred; then an exception is raised. */ static int -setipaddr(const char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int af) +setipaddr(socket_state *state, const char *name, struct sockaddr *addr_ret, + size_t addr_ret_size, int af) { struct addrinfo hints, *res; int error; @@ -1095,7 +1133,7 @@ setipaddr(const char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int outcome of the first call. */ if (error) { res = NULL; // no-op, remind us that it is invalid; gh-100795 - set_gaierror(error); + set_gaierror(state, error); return -1; } switch (res->ai_family) { @@ -1206,7 +1244,7 @@ setipaddr(const char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int Py_END_ALLOW_THREADS if (error) { res = NULL; // no-op, remind us that it is invalid; gh-100795 - set_gaierror(error); + set_gaierror(state, error); return -1; } if (res->ai_addrlen < addr_ret_size) @@ -1889,7 +1927,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, return 0; } struct sockaddr_in* addr = &addrbuf->in; - result = setipaddr(host.buf, (struct sockaddr *)addr, + result = setipaddr(s->state, host.buf, (struct sockaddr *)addr, sizeof(*addr), AF_INET); idna_cleanup(&host); if (result < 0) @@ -1934,7 +1972,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, return 0; } struct sockaddr_in6* addr = &addrbuf->in6; - result = setipaddr(host.buf, (struct sockaddr *)addr, + result = setipaddr(s->state, host.buf, (struct sockaddr *)addr, sizeof(*addr), AF_INET6); idna_cleanup(&host); if (result < 0) @@ -2813,10 +2851,6 @@ struct sock_accept { }; #if defined(HAVE_ACCEPT) || defined(HAVE_ACCEPT4) -#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) -/* accept4() is available on Linux 2.6.28+ and glibc 2.10 */ -static int accept4_works = -1; -#endif static int sock_accept_impl(PySocketSockObject *s, void *data) @@ -2835,15 +2869,16 @@ sock_accept_impl(PySocketSockObject *s, void *data) #endif #if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) - if (accept4_works != 0) { + socket_state *state = s->state; + if (state->accept4_works != 0) { ctx->result = accept4(s->sock_fd, addr, paddrlen, SOCK_CLOEXEC); - if (ctx->result == INVALID_SOCKET && accept4_works == -1) { + if (ctx->result == INVALID_SOCKET && state->accept4_works == -1) { /* On Linux older than 2.6.28, accept4() fails with ENOSYS */ - accept4_works = (errno != ENOSYS); + state->accept4_works = (errno != ENOSYS); } } - if (accept4_works == 0) + if (state->accept4_works == 0) ctx->result = accept(s->sock_fd, addr, paddrlen); #else ctx->result = accept(s->sock_fd, addr, paddrlen); @@ -2896,7 +2931,8 @@ sock_accept(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) #else #if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) - if (!accept4_works) + socket_state *state = s->state; + if (!state->accept4_works) #endif { if (_Py_set_inheritable(newfd, 0, NULL) < 0) { @@ -5219,13 +5255,23 @@ sock_finalize(PySocketSockObject *s) PyErr_SetRaisedException(exc); } +static int +sock_traverse(PySocketSockObject *s, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(s)); + return 0; +} + static void sock_dealloc(PySocketSockObject *s) { - if (PyObject_CallFinalizerFromDealloc((PyObject *)s) < 0) + if (PyObject_CallFinalizerFromDealloc((PyObject *)s) < 0) { return; - - Py_TYPE(s)->tp_free((PyObject *)s); + } + PyTypeObject *tp = Py_TYPE(s); + PyObject_GC_UnTrack(s); + tp->tp_free((PyObject *)s); + Py_DECREF(tp); } @@ -5277,12 +5323,6 @@ sock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) /* Initialize a new socket object. */ -#ifdef SOCK_CLOEXEC -/* socket() and socketpair() fail with EINVAL on Linux kernel older - * than 2.6.27 if SOCK_CLOEXEC flag is set in the socket type. */ -static int sock_cloexec_works = -1; -#endif - /*ARGSUSED*/ #ifndef HAVE_SOCKET @@ -5310,10 +5350,11 @@ sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto, { SOCKET_T fd = INVALID_SOCKET; + socket_state *state = find_module_state_by_def(Py_TYPE(self)); #ifndef MS_WINDOWS #ifdef SOCK_CLOEXEC - int *atomic_flag_works = &sock_cloexec_works; + int *atomic_flag_works = &state->sock_cloexec_works; #else int *atomic_flag_works = NULL; #endif @@ -5468,15 +5509,15 @@ sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto, /* UNIX */ Py_BEGIN_ALLOW_THREADS #ifdef SOCK_CLOEXEC - if (sock_cloexec_works != 0) { + if (state->sock_cloexec_works != 0) { fd = socket(family, type | SOCK_CLOEXEC, proto); - if (sock_cloexec_works == -1) { + if (state->sock_cloexec_works == -1) { if (fd >= 0) { - sock_cloexec_works = 1; + state->sock_cloexec_works = 1; } else if (errno == EINVAL) { /* Linux older than 2.6.27 does not support SOCK_CLOEXEC */ - sock_cloexec_works = 0; + state->sock_cloexec_works = 0; fd = socket(family, type, proto); } } @@ -5499,7 +5540,7 @@ sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto, } #endif } - if (init_sockobject(self, fd, family, type, proto) == -1) { + if (init_sockobject(state, self, fd, family, type, proto) == -1) { SOCKETCLOSE(fd); return -1; } @@ -5511,55 +5552,26 @@ sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto, /* Type object for socket objects. */ -static PyTypeObject sock_type = { - PyVarObject_HEAD_INIT(0, 0) /* Must fill in type value later */ - "_socket.socket", /* tp_name */ - sizeof(PySocketSockObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)sock_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)sock_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - sock_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - sock_methods, /* tp_methods */ - sock_memberlist, /* tp_members */ - sock_getsetlist, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - sock_initobj, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - sock_new, /* tp_new */ - PyObject_Del, /* tp_free */ - 0, /* tp_is_gc */ - 0, /* tp_bases */ - 0, /* tp_mro */ - 0, /* tp_cache */ - 0, /* tp_subclasses */ - 0, /* tp_weaklist */ - 0, /* tp_del */ - 0, /* tp_version_tag */ - (destructor)sock_finalize, /* tp_finalize */ +static PyType_Slot sock_slots[] = { + {Py_tp_dealloc, sock_dealloc}, + {Py_tp_traverse, sock_traverse}, + {Py_tp_repr, sock_repr}, + {Py_tp_doc, (void *)sock_doc}, + {Py_tp_methods, sock_methods}, + {Py_tp_members, sock_memberlist}, + {Py_tp_getset, sock_getsetlist}, + {Py_tp_init, sock_initobj}, + {Py_tp_new, sock_new}, + {Py_tp_finalize, sock_finalize}, + {0, NULL}, +}; + +static PyType_Spec sock_spec = { + .name = "_socket.socket", + .basicsize = sizeof(PySocketSockObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = sock_slots, }; @@ -5687,8 +5699,12 @@ socket_gethostbyname(PyObject *self, PyObject *args) if (PySys_Audit("socket.gethostbyname", "O", args) < 0) { goto finally; } - if (setipaddr(name, (struct sockaddr *)&addrbuf, sizeof(addrbuf), AF_INET) < 0) + socket_state *state = get_module_state(self); + int rc = setipaddr(state, name, (struct sockaddr *)&addrbuf, + sizeof(addrbuf), AF_INET); + if (rc < 0) { goto finally; + } ret = make_ipv4_addr(&addrbuf); finally: PyMem_Free(name); @@ -5719,7 +5735,8 @@ sock_decode_hostname(const char *name) /* Convenience function common to gethostbyname_ex and gethostbyaddr */ static PyObject * -gethost_common(struct hostent *h, struct sockaddr *addr, size_t alen, int af) +gethost_common(socket_state *state, struct hostent *h, struct sockaddr *addr, + size_t alen, int af) { char **pch; PyObject *rtn_tuple = (PyObject *)NULL; @@ -5730,7 +5747,7 @@ gethost_common(struct hostent *h, struct sockaddr *addr, size_t alen, int af) if (h == NULL) { /* Let's get real error message to return */ - set_herror(h_errno); + set_herror(state, h_errno); return NULL; } @@ -5877,8 +5894,10 @@ socket_gethostbyname_ex(PyObject *self, PyObject *args) if (PySys_Audit("socket.gethostbyname", "O", args) < 0) { goto finally; } - if (setipaddr(name, SAS2SA(&addr), sizeof(addr), AF_INET) < 0) + socket_state *state = get_module_state(self); + if (setipaddr(state, name, SAS2SA(&addr), sizeof(addr), AF_INET) < 0) { goto finally; + } Py_BEGIN_ALLOW_THREADS #ifdef HAVE_GETHOSTBYNAME_R #if defined(HAVE_GETHOSTBYNAME_R_6_ARG) @@ -5904,7 +5923,7 @@ socket_gethostbyname_ex(PyObject *self, PyObject *args) Therefore, we cast the sockaddr_storage into sockaddr to access sa_family. */ sa = SAS2SA(&addr); - ret = gethost_common(h, SAS2SA(&addr), sizeof(addr), + ret = gethost_common(state, h, SAS2SA(&addr), sizeof(addr), sa->sa_family); #ifdef USE_GETHOSTBYNAME_LOCK PyThread_release_lock(netdb_lock); @@ -5960,8 +5979,10 @@ socket_gethostbyaddr(PyObject *self, PyObject *args) goto finally; } af = AF_UNSPEC; - if (setipaddr(ip_num, sa, sizeof(addr), af) < 0) + socket_state *state = get_module_state(self); + if (setipaddr(state, ip_num, sa, sizeof(addr), af) < 0) { goto finally; + } af = sa->sa_family; ap = NULL; /* al = 0; */ @@ -6002,7 +6023,7 @@ socket_gethostbyaddr(PyObject *self, PyObject *args) h = gethostbyaddr(ap, al, af); #endif /* HAVE_GETHOSTBYNAME_R */ Py_END_ALLOW_THREADS - ret = gethost_common(h, SAS2SA(&addr), sizeof(addr), af); + ret = gethost_common(state, h, SAS2SA(&addr), sizeof(addr), af); #ifdef USE_GETHOSTBYNAME_LOCK PyThread_release_lock(netdb_lock); #endif @@ -6221,8 +6242,9 @@ socket_socketpair(PyObject *self, PyObject *args) SOCKET_T sv[2]; int family, type = SOCK_STREAM, proto = 0; PyObject *res = NULL; + socket_state *state = get_module_state(self); #ifdef SOCK_CLOEXEC - int *atomic_flag_works = &sock_cloexec_works; + int *atomic_flag_works = &state->sock_cloexec_works; #else int *atomic_flag_works = NULL; #endif @@ -6240,15 +6262,15 @@ socket_socketpair(PyObject *self, PyObject *args) /* Create a pair of socket fds */ Py_BEGIN_ALLOW_THREADS #ifdef SOCK_CLOEXEC - if (sock_cloexec_works != 0) { + if (state->sock_cloexec_works != 0) { ret = socketpair(family, type | SOCK_CLOEXEC, proto, sv); - if (sock_cloexec_works == -1) { + if (state->sock_cloexec_works == -1) { if (ret >= 0) { - sock_cloexec_works = 1; + state->sock_cloexec_works = 1; } else if (errno == EINVAL) { /* Linux older than 2.6.27 does not support SOCK_CLOEXEC */ - sock_cloexec_works = 0; + state->sock_cloexec_works = 0; ret = socketpair(family, type, proto, sv); } } @@ -6268,10 +6290,10 @@ socket_socketpair(PyObject *self, PyObject *args) if (_Py_set_inheritable(sv[1], 0, atomic_flag_works) < 0) goto finally; - s0 = new_sockobject(sv[0], family, type, proto); + s0 = new_sockobject(state, sv[0], family, type, proto); if (s0 == NULL) goto finally; - s1 = new_sockobject(sv[1], family, type, proto); + s1 = new_sockobject(state, sv[1], family, type, proto); if (s1 == NULL) goto finally; res = PyTuple_Pack(2, s0, s1); @@ -6726,7 +6748,8 @@ socket_getaddrinfo(PyObject *self, PyObject *args, PyObject* kwargs) Py_END_ALLOW_THREADS if (error) { res0 = NULL; // gh-100795 - set_gaierror(error); + socket_state *state = get_module_state(self); + set_gaierror(state, error); goto err; } @@ -6825,7 +6848,8 @@ socket_getnameinfo(PyObject *self, PyObject *args) Py_END_ALLOW_THREADS if (error) { res = NULL; // gh-100795 - set_gaierror(error); + socket_state *state = get_module_state(self); + set_gaierror(state, error); goto fail; } if (res->ai_next) { @@ -6857,7 +6881,8 @@ socket_getnameinfo(PyObject *self, PyObject *args) error = getnameinfo(res->ai_addr, (socklen_t) res->ai_addrlen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), flags); if (error) { - set_gaierror(error); + socket_state *state = get_module_state(self); + set_gaierror(state, error); goto fail; } @@ -6883,11 +6908,12 @@ Get host and port for a sockaddr."); static PyObject * socket_getdefaulttimeout(PyObject *self, PyObject *Py_UNUSED(ignored)) { - if (defaulttimeout < 0) { + socket_state *state = get_module_state(self); + if (state->defaulttimeout < 0) { Py_RETURN_NONE; } else { - double seconds = _PyTime_AsSecondsDouble(defaulttimeout); + double seconds = _PyTime_AsSecondsDouble(state->defaulttimeout); return PyFloat_FromDouble(seconds); } } @@ -6907,7 +6933,8 @@ socket_setdefaulttimeout(PyObject *self, PyObject *arg) if (socket_parse_timeout(&timeout, arg) < 0) return NULL; - defaulttimeout = timeout; + socket_state *state = get_module_state(self); + state->defaulttimeout = timeout; Py_RETURN_NONE; } @@ -7293,7 +7320,7 @@ sock_destroy_api(PyObject *capsule) } static PySocketModule_APIObject * -sock_get_api(void) +sock_get_api(socket_state *state) { PySocketModule_APIObject *capi = PyMem_Malloc(sizeof(PySocketModule_APIObject)); if (capi == NULL) { @@ -7301,7 +7328,7 @@ sock_get_api(void) return NULL; } - capi->Sock_Type = (PyTypeObject *)Py_NewRef(&sock_type); + capi->Sock_Type = (PyTypeObject *)Py_NewRef(state->sock_type); capi->error = Py_NewRef(PyExc_OSError); capi->timeout_error = Py_NewRef(PyExc_TimeoutError); return capi; @@ -7323,47 +7350,38 @@ PyDoc_STRVAR(socket_doc, \n\ See the socket module for documentation."); -static struct PyModuleDef socketmodule = { - PyModuleDef_HEAD_INIT, - PySocket_MODULE_NAME, - socket_doc, - -1, - socket_methods, - NULL, - NULL, - NULL, - NULL -}; - -PyMODINIT_FUNC -PyInit__socket(void) +static int +socket_exec(PyObject *m) { - PyObject *m = NULL; - if (!os_init()) { goto error; } - Py_SET_TYPE(&sock_type, &PyType_Type); - m = PyModule_Create(&socketmodule); - if (m == NULL) { - goto error; - } + socket_state *state = get_module_state(m); + state->defaulttimeout = _PYTIME_FROMSECONDS(-1); + +#if defined(HAVE_ACCEPT) || defined(HAVE_ACCEPT4) +#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) + state->accept4_works = -1; +#endif +#endif + +#ifdef SOCK_CLOEXEC + state->sock_cloexec_works = -1; +#endif #define ADD_EXC(MOD, NAME, VAR, BASE) do { \ VAR = PyErr_NewException("socket." NAME, BASE, NULL); \ if (VAR == NULL) { \ goto error; \ } \ - int rc = PyModule_AddObjectRef(MOD, NAME, VAR); \ - Py_DECREF(VAR); \ - if (rc < 0) { \ + if (PyModule_AddObjectRef(MOD, NAME, VAR) < 0) { \ goto error; \ } \ } while (0) - ADD_EXC(m, "herror", socket_herror, PyExc_OSError); - ADD_EXC(m, "gaierror", socket_gaierror, PyExc_OSError); + ADD_EXC(m, "herror", state->socket_herror, PyExc_OSError); + ADD_EXC(m, "gaierror", state->socket_gaierror, PyExc_OSError); #undef ADD_EXC @@ -7373,10 +7391,16 @@ PyInit__socket(void) if (PyModule_AddObjectRef(m, "timeout", PyExc_TimeoutError) < 0) { goto error; } - if (PyModule_AddObjectRef(m, "SocketType", (PyObject *)&sock_type) < 0) { + + PyObject *sock_type = PyType_FromMetaclass(NULL, m, &sock_spec, NULL); + if (sock_type == NULL) { + goto error; + } + state->sock_type = (PyTypeObject *)sock_type; + if (PyModule_AddObjectRef(m, "SocketType", sock_type) < 0) { goto error; } - if (PyModule_AddType(m, &sock_type) < 0) { + if (PyModule_AddType(m, state->sock_type) < 0) { goto error; } @@ -7391,7 +7415,7 @@ PyInit__socket(void) } /* Export C API */ - PySocketModule_APIObject *capi = sock_get_api(); + PySocketModule_APIObject *capi = sock_get_api(state); if (capi == NULL) { goto error; } @@ -8813,9 +8837,57 @@ PyInit__socket(void) #undef ADD_INT_CONST #undef ADD_STR_CONST - return m; + return 0; error: - Py_XDECREF(m); - return NULL; + return -1; +} + +static struct PyModuleDef_Slot socket_slots[] = { + {Py_mod_exec, socket_exec}, + {0, NULL}, +}; + +static int +socket_traverse(PyObject *mod, visitproc visit, void *arg) +{ + socket_state *state = get_module_state(mod); + Py_VISIT(state->sock_type); + Py_VISIT(state->socket_herror); + Py_VISIT(state->socket_gaierror); + return 0; +} + +static int +socket_clear(PyObject *mod) +{ + socket_state *state = get_module_state(mod); + Py_CLEAR(state->sock_type); + Py_CLEAR(state->socket_herror); + Py_CLEAR(state->socket_gaierror); + return 0; +} + +static void +socket_free(void *mod) +{ + (void)socket_clear((PyObject *)mod); +} + +static struct PyModuleDef socketmodule = { + .m_base = PyModuleDef_HEAD_INIT, + .m_name = PySocket_MODULE_NAME, + .m_doc = socket_doc, + .m_size = sizeof(socket_state), + .m_methods = socket_methods, + .m_slots = socket_slots, + .m_traverse = socket_traverse, + .m_clear = socket_clear, + .m_free = socket_free, +}; + +PyMODINIT_FUNC +PyInit__socket(void) +{ + return PyModuleDef_Init(&socketmodule); } diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h index f31ba532a6c6..f5ca00450ee9 100644 --- a/Modules/socketmodule.h +++ b/Modules/socketmodule.h @@ -322,6 +322,7 @@ typedef struct { sets a Python exception */ _PyTime_t sock_timeout; /* Operation timeout in seconds; 0.0 means non-blocking */ + struct _socket_state *state; } PySocketSockObject; /* --- C API ----------------------------------------------------*/ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 0620c7e13925..e36024ad16c2 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -392,7 +392,6 @@ Modules/_decimal/_decimal.c - PyDecSignalDictMixin_Type - Modules/_decimal/_decimal.c - PyDec_Type - Modules/ossaudiodev.c - OSSAudioType - Modules/ossaudiodev.c - OSSMixerType - -Modules/socketmodule.c - sock_type - Modules/xxmodule.c - Null_Type - Modules/xxmodule.c - Str_Type - Modules/xxmodule.c - Xxo_Type - @@ -416,8 +415,6 @@ Modules/_cursesmodule.c - PyCursesError - Modules/_decimal/_decimal.c - DecimalException - Modules/_tkinter.c - Tkinter_TclError - Modules/ossaudiodev.c - OSSAudioError - -Modules/socketmodule.c - socket_herror - -Modules/socketmodule.c - socket_gaierror - Modules/xxlimited_35.c - ErrorObject - Modules/xxmodule.c - ErrorObject - @@ -514,8 +511,6 @@ Modules/cjkcodecs/cjkcodecs.h - mapping_list - Modules/readline.c - libedit_append_replace_history_offset - Modules/readline.c - using_libedit_emulation - Modules/readline.c - libedit_history_start - -Modules/socketmodule.c - accept4_works - -Modules/socketmodule.c - sock_cloexec_works - ##----------------------- ## state @@ -541,4 +536,3 @@ Modules/readline.c - sigwinch_ohandler - Modules/readline.c - completed_input_string - Modules/rotatingtree.c - random_stream - Modules/rotatingtree.c - random_value - -Modules/socketmodule.c - defaulttimeout - From webhook-mailer at python.org Sat Apr 8 21:59:15 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sun, 09 Apr 2023 01:59:15 -0000 Subject: [Python-checkins] Document `asyncio` performance improvement in What's New (#103370) Message-ID: https://github.com/python/cpython/commit/63dc969ec6129704c3b23b384ecfa8e485d6c4cb commit: 63dc969ec6129704c3b23b384ecfa8e485d6c4cb branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-04-09T07:29:08+05:30 summary: Document `asyncio` performance improvement in What's New (#103370) Co-authored-by: Alex Waygood files: M Doc/whatsnew/3.12.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 66e40ef7326c..651caed864fe 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -210,6 +210,11 @@ array asyncio ------- +* The performance of writing to sockets in :mod:`asyncio` has been + significantly improved. ``asyncio`` now avoids unnecessary copying when + writing to sockets and uses :meth:`~socket.socket.sendmsg` if the platform + supports it. (Contributed by Kumar Aditya in :gh:`91166`.) + * On Linux, :mod:`asyncio` uses :class:`~asyncio.PidfdChildWatcher` by default if :func:`os.pidfd_open` is available and functional instead of :class:`~asyncio.ThreadedChildWatcher`. From webhook-mailer at python.org Sat Apr 8 22:02:22 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sun, 09 Apr 2023 02:02:22 -0000 Subject: [Python-checkins] Docs: Fix broken reference `__getitem__` in `string.rst` (#103371) Message-ID: https://github.com/python/cpython/commit/83af8f268629139b9628ff53617671469167146a commit: 83af8f268629139b9628ff53617671469167146a branch: main author: yuki committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-04-09T07:32:16+05:30 summary: Docs: Fix broken reference `__getitem__` in `string.rst` (#103371) files: M Doc/library/string.rst diff --git a/Doc/library/string.rst b/Doc/library/string.rst index 5ada82732818..f55074cc5827 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -235,7 +235,7 @@ dictionary keys (e.g., the strings ``'10'`` or ``':-]'``) within a format string The *arg_name* can be followed by any number of index or attribute expressions. An expression of the form ``'.name'`` selects the named attribute using :func:`getattr`, while an expression of the form ``'[index]'`` -does an index lookup using :func:`__getitem__`. +does an index lookup using :meth:`~object.__getitem__`. .. versionchanged:: 3.1 The positional argument specifiers can be omitted for :meth:`str.format`, From webhook-mailer at python.org Sat Apr 8 22:05:57 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sun, 09 Apr 2023 02:05:57 -0000 Subject: [Python-checkins] gh-102799: use `sys.exception()` instead of `sys.exc_info()` in pdb (#103294) Message-ID: https://github.com/python/cpython/commit/264b87f7fd0634485b9b4d21df49bec3401d7b2a commit: 264b87f7fd0634485b9b4d21df49bec3401d7b2a branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-04-09T07:35:50+05:30 summary: gh-102799: use `sys.exception()` instead of `sys.exc_info()` in pdb (#103294) files: M Lib/pdb.py diff --git a/Lib/pdb.py b/Lib/pdb.py index e043b0d46f7d..e03142e9b5d8 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1258,7 +1258,7 @@ def _getval_except(self, arg, frame=None): return _rstr('** raised %s **' % self._format_exc(exc)) def _error_exc(self): - exc = sys.exc_info()[1] + exc = sys.exception() self.error(self._format_exc(exc)) def _msg_val_func(self, arg, func): @@ -1755,9 +1755,10 @@ def post_mortem(t=None): """ # handling the default if t is None: - # sys.exc_info() returns (type, value, traceback) if an exception is - # being handled, otherwise it returns None - t = sys.exc_info()[2] + exc = sys.exception() + if exc is not None: + t = exc.__traceback__ + if t is None: raise ValueError("A valid traceback must be passed if no " "exception is being handled") @@ -1841,18 +1842,18 @@ def main(): except Restart: print("Restarting", target, "with arguments:") print("\t" + " ".join(sys.argv[1:])) - except SystemExit: + except SystemExit as e: # In most cases SystemExit does not warrant a post-mortem session. print("The program exited via sys.exit(). Exit status:", end=' ') - print(sys.exc_info()[1]) + print(e) except SyntaxError: traceback.print_exc() sys.exit(1) - except: + except BaseException as e: traceback.print_exc() print("Uncaught exception. Entering post mortem debugging") print("Running 'cont' or 'step' will restart the program") - t = sys.exc_info()[2] + t = e.__traceback__ pdb.interaction(None, t) print("Post mortem debugger finished. The " + target + " will be restarted") From webhook-mailer at python.org Sun Apr 9 02:39:10 2023 From: webhook-mailer at python.org (hugovk) Date: Sun, 09 Apr 2023 06:39:10 -0000 Subject: [Python-checkins] CI: Do not allow merge if labelled DO-NOT-MERGE (#103337) Message-ID: https://github.com/python/cpython/commit/090e26ea807aa414d6a6a01d9365b0288c10a5db commit: 090e26ea807aa414d6a6a01d9365b0288c10a5db branch: main author: Hugo van Kemenade committer: hugovk date: 2023-04-09T09:39:03+03:00 summary: CI: Do not allow merge if labelled DO-NOT-MERGE (#103337) Co-authored-by: C.A.M. Gerlach files: A .github/workflows/require-pr-label.yml diff --git a/.github/workflows/require-pr-label.yml b/.github/workflows/require-pr-label.yml new file mode 100644 index 000000000000..e847bae155e2 --- /dev/null +++ b/.github/workflows/require-pr-label.yml @@ -0,0 +1,17 @@ +name: Check labels + +on: + pull_request: + types: [opened, reopened, labeled, unlabeled, synchronize] + +jobs: + label: + name: DO-NOT-MERGE + runs-on: ubuntu-latest + + steps: + - uses: mheap/github-action-required-labels at v4 + with: + mode: exactly + count: 0 + labels: "DO-NOT-MERGE" From webhook-mailer at python.org Sun Apr 9 03:01:56 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 09 Apr 2023 07:01:56 -0000 Subject: [Python-checkins] CI: Do not allow merge if labelled DO-NOT-MERGE (GH-103337) Message-ID: https://github.com/python/cpython/commit/da3b77b828f4218b3c67185c80413742fb4d2a06 commit: da3b77b828f4218b3c67185c80413742fb4d2a06 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-09T00:01:49-07:00 summary: CI: Do not allow merge if labelled DO-NOT-MERGE (GH-103337) (cherry picked from commit 090e26ea807aa414d6a6a01d9365b0288c10a5db) Co-authored-by: Hugo van Kemenade Co-authored-by: C.A.M. Gerlach files: A .github/workflows/require-pr-label.yml diff --git a/.github/workflows/require-pr-label.yml b/.github/workflows/require-pr-label.yml new file mode 100644 index 000000000000..e847bae155e2 --- /dev/null +++ b/.github/workflows/require-pr-label.yml @@ -0,0 +1,17 @@ +name: Check labels + +on: + pull_request: + types: [opened, reopened, labeled, unlabeled, synchronize] + +jobs: + label: + name: DO-NOT-MERGE + runs-on: ubuntu-latest + + steps: + - uses: mheap/github-action-required-labels at v4 + with: + mode: exactly + count: 0 + labels: "DO-NOT-MERGE" From webhook-mailer at python.org Sun Apr 9 03:43:08 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 09 Apr 2023 07:43:08 -0000 Subject: [Python-checkins] Add hugovk as a .github code owner (GH-103394) Message-ID: https://github.com/python/cpython/commit/c330b4a3e7b34308ad97d51de9ab8f4e51a0805c commit: c330b4a3e7b34308ad97d51de9ab8f4e51a0805c branch: main author: Hugo van Kemenade committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-09T00:43:01-07:00 summary: Add hugovk as a .github code owner (GH-103394) Automerge-Triggered-By: GH:hugovk files: M .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index fc1bb3388976..60af0519cdb7 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -5,7 +5,7 @@ # https://git-scm.com/docs/gitignore#_pattern_format # GitHub -.github/** @ezio-melotti +.github/** @ezio-melotti @hugovk # Build system configure* @erlend-aasland @corona10 From webhook-mailer at python.org Sun Apr 9 04:12:50 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sun, 09 Apr 2023 08:12:50 -0000 Subject: [Python-checkins] build(deps): bump actions/stale from 7 to 8 (#103169) Message-ID: https://github.com/python/cpython/commit/5d4afc45b9567d227ea9a9988d58404662fce58c commit: 5d4afc45b9567d227ea9a9988d58404662fce58c branch: main author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-04-09T13:42:43+05:30 summary: build(deps): bump actions/stale from 7 to 8 (#103169) Bumps [actions/stale](https://github.com/actions/stale) from 7 to 8. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v7...v8) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> files: M .github/workflows/stale.yml diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 07dbcfe31d65..d79e856c87e7 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -15,7 +15,7 @@ jobs: steps: - name: "Check PRs" - uses: actions/stale at v7 + uses: actions/stale at v8 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-pr-message: 'This PR is stale because it has been open for 30 days with no activity.' From webhook-mailer at python.org Sun Apr 9 04:13:47 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sun, 09 Apr 2023 08:13:47 -0000 Subject: [Python-checkins] Fix typos in test_tempfile.py (#102841) Message-ID: https://github.com/python/cpython/commit/d9305f8e9d3e0f6267286c2da4b24e97b7a569f2 commit: d9305f8e9d3e0f6267286c2da4b24e97b7a569f2 branch: main author: JakobDev committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-04-09T13:43:40+05:30 summary: Fix typos in test_tempfile.py (#102841) files: M Lib/test/test_tempfile.py diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index 90155487cff5..11a43aca17e8 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -1016,7 +1016,7 @@ def use_closed(): self.assertRaises(ValueError, use_closed) def test_context_man_not_del_on_close_if_delete_on_close_false(self): - # Issue gh-58451: tempfile.NamedTemporaryFile is not particulary useful + # Issue gh-58451: tempfile.NamedTemporaryFile is not particularly useful # on Windows # A NamedTemporaryFile is NOT deleted when closed if # delete_on_close=False, but is deleted on context manager exit @@ -1608,7 +1608,7 @@ def test_explicit_cleanup(self): finally: os.rmdir(dir) - def test_explict_cleanup_ignore_errors(self): + def test_explicit_cleanup_ignore_errors(self): """Test that cleanup doesn't return an error when ignoring them.""" with tempfile.TemporaryDirectory() as working_dir: temp_dir = self.do_create( From webhook-mailer at python.org Sun Apr 9 04:19:00 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sun, 09 Apr 2023 08:19:00 -0000 Subject: [Python-checkins] gh-103300: Fix `Popen.wait()` deadlock in patchcheck.py (#103301) Message-ID: https://github.com/python/cpython/commit/86d20441557bedbea3dadd5d0818a492148335bd commit: 86d20441557bedbea3dadd5d0818a492148335bd branch: main author: Oleg Iarygin committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-04-09T13:48:53+05:30 summary: gh-103300: Fix `Popen.wait()` deadlock in patchcheck.py (#103301) files: M Tools/patchcheck/patchcheck.py diff --git a/Tools/patchcheck/patchcheck.py b/Tools/patchcheck/patchcheck.py index 6dcf61206619..44a6fb8c660c 100755 --- a/Tools/patchcheck/patchcheck.py +++ b/Tools/patchcheck/patchcheck.py @@ -130,9 +130,10 @@ def changed_files(base_branch=None): with subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, cwd=SRCDIR) as st: - if st.wait() != 0: + git_file_status, _ = st.communicate() + if st.returncode != 0: sys.exit(f'error running {cmd}') - for line in st.stdout: + for line in git_file_status.splitlines(): line = line.decode().rstrip() status_text, filename = line.split(maxsplit=1) status = set(status_text) From webhook-mailer at python.org Sun Apr 9 04:26:59 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sun, 09 Apr 2023 08:26:59 -0000 Subject: [Python-checkins] ctypes docs: fix missing `not` in variadic functions section (#102611) Message-ID: https://github.com/python/cpython/commit/975d220bbed0e7a15b62f1d2d03557740a55f68d commit: 975d220bbed0e7a15b62f1d2d03557740a55f68d branch: main author: mara004 committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-04-09T13:56:52+05:30 summary: ctypes docs: fix missing `not` in variadic functions section (#102611) files: M Doc/library/ctypes.rst diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index d49d702e9e79..81509c0920bb 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -390,7 +390,7 @@ regular, non-variadic, function arguments: libc.printf.argtypes = [ctypes.c_char_p] -Because specifying the attribute does inhibit portability it is advised to always +Because specifying the attribute does not inhibit portability it is advised to always specify ``argtypes`` for all variadic functions. From webhook-mailer at python.org Sun Apr 9 04:43:28 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sun, 09 Apr 2023 08:43:28 -0000 Subject: [Python-checkins] Remove useless symbol in pystats.h (#101864) Message-ID: https://github.com/python/cpython/commit/45b4b37fc26f288fabb27dc08b253121697c517b commit: 45b4b37fc26f288fabb27dc08b253121697c517b branch: main author: Stepfen Shawn committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-04-09T14:13:21+05:30 summary: Remove useless symbol in pystats.h (#101864) files: M Include/pystats.h diff --git a/Include/pystats.h b/Include/pystats.h index 25ed4bddc724..4b961bad2a43 100644 --- a/Include/pystats.h +++ b/Include/pystats.h @@ -72,8 +72,6 @@ typedef struct _object_stats { uint64_t type_cache_collisions; } ObjectStats; -# - typedef struct _stats { OpcodeStats opcode_stats[256]; CallStats call_stats; From webhook-mailer at python.org Sun Apr 9 04:44:56 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 09 Apr 2023 08:44:56 -0000 Subject: [Python-checkins] Gh-68586: use run_python_until_end in test_capi (GH-102729) Message-ID: https://github.com/python/cpython/commit/8317d51996e68d8bb205385c1d47a9edcd128e7b commit: 8317d51996e68d8bb205385c1d47a9edcd128e7b branch: main author: Furkan Onder committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-09T01:44:49-07:00 summary: Gh-68586: use run_python_until_end in test_capi (GH-102729) Co-authored-by: Aidin Gharibnavaz Automerge-Triggered-By: GH:kumaraditya303 files: M Lib/test/test_capi/test_misc.py diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index c34ee578b5c8..637adc01a331 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -21,7 +21,7 @@ from test.support import import_helper from test.support import threading_helper from test.support import warnings_helper -from test.support.script_helper import assert_python_failure, assert_python_ok +from test.support.script_helper import assert_python_failure, assert_python_ok, run_python_until_end try: import _posixsubprocess except ImportError: @@ -69,21 +69,17 @@ def test_instancemethod(self): @support.requires_subprocess() def test_no_FatalError_infinite_loop(self): - with support.SuppressCrashReport(): - p = subprocess.Popen([sys.executable, "-c", - 'import _testcapi;' - '_testcapi.crash_no_current_thread()'], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True) - (out, err) = p.communicate() - self.assertEqual(out, '') + run_result, _cmd_line = run_python_until_end( + '-c', 'import _testcapi; _testcapi.crash_no_current_thread()', + ) + _rc, out, err = run_result + self.assertEqual(out, b'') # This used to cause an infinite loop. msg = ("Fatal Python error: PyThreadState_Get: " "the function must be called with the GIL held, " "after Python initialization and before Python finalization, " "but the GIL is released " - "(the current Python thread state is NULL)") + "(the current Python thread state is NULL)").encode() self.assertTrue(err.rstrip().startswith(msg), err) From webhook-mailer at python.org Sun Apr 9 11:48:55 2023 From: webhook-mailer at python.org (barneygale) Date: Sun, 09 Apr 2023 15:48:55 -0000 Subject: [Python-checkins] GH-103379: Fix up old tests for `pathlib.PurePath._parse_path` (GH-103380) Message-ID: https://github.com/python/cpython/commit/0a675f4bb57d01a5e69f8f58ae934ad7ca501a8d commit: 0a675f4bb57d01a5e69f8f58ae934ad7ca501a8d branch: main author: Barney Gale committer: barneygale date: 2023-04-09T16:48:45+01:00 summary: GH-103379: Fix up old tests for `pathlib.PurePath._parse_path` (GH-103380) Co-authored-by: Terry Jan Reedy files: M Lib/test/test_pathlib.py diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 8b6e012b730d..fe75f1c2580b 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -24,116 +24,6 @@ grp = pwd = None -class _BaseFlavourTest(object): - - def _check_parse_parts(self, arg, expected): - def f(parts): - path = self.cls(*parts)._raw_path - return self.cls._parse_path(path) - sep = self.flavour.sep - altsep = self.flavour.altsep - actual = f([x.replace('/', sep) for x in arg]) - self.assertEqual(actual, expected) - if altsep: - actual = f([x.replace('/', altsep) for x in arg]) - self.assertEqual(actual, expected) - - def test_parse_parts_common(self): - check = self._check_parse_parts - sep = self.flavour.sep - # Unanchored parts. - check([], ('', '', [])) - check(['a'], ('', '', ['a'])) - check(['a/'], ('', '', ['a'])) - check(['a', 'b'], ('', '', ['a', 'b'])) - # Expansion. - check(['a/b'], ('', '', ['a', 'b'])) - check(['a/b/'], ('', '', ['a', 'b'])) - check(['a', 'b/c', 'd'], ('', '', ['a', 'b', 'c', 'd'])) - # Collapsing and stripping excess slashes. - check(['a', 'b//c', 'd'], ('', '', ['a', 'b', 'c', 'd'])) - check(['a', 'b/c/', 'd'], ('', '', ['a', 'b', 'c', 'd'])) - # Eliminating standalone dots. - check(['.'], ('', '', [])) - check(['.', '.', 'b'], ('', '', ['b'])) - check(['a', '.', 'b'], ('', '', ['a', 'b'])) - check(['a', '.', '.'], ('', '', ['a'])) - # The first part is anchored. - check(['/a/b'], ('', sep, [sep, 'a', 'b'])) - check(['/a', 'b'], ('', sep, [sep, 'a', 'b'])) - check(['/a/', 'b'], ('', sep, [sep, 'a', 'b'])) - # Ignoring parts before an anchored part. - check(['a', '/b', 'c'], ('', sep, [sep, 'b', 'c'])) - check(['a', '/b', '/c'], ('', sep, [sep, 'c'])) - - -class PosixFlavourTest(_BaseFlavourTest, unittest.TestCase): - cls = pathlib.PurePosixPath - flavour = pathlib.PurePosixPath._flavour - - def test_parse_parts(self): - check = self._check_parse_parts - # Collapsing of excess leading slashes, except for the double-slash - # special case. - check(['//a', 'b'], ('', '//', ['//', 'a', 'b'])) - check(['///a', 'b'], ('', '/', ['/', 'a', 'b'])) - check(['////a', 'b'], ('', '/', ['/', 'a', 'b'])) - # Paths which look like NT paths aren't treated specially. - check(['c:a'], ('', '', ['c:a'])) - check(['c:\\a'], ('', '', ['c:\\a'])) - check(['\\a'], ('', '', ['\\a'])) - - -class NTFlavourTest(_BaseFlavourTest, unittest.TestCase): - cls = pathlib.PureWindowsPath - flavour = pathlib.PureWindowsPath._flavour - - def test_parse_parts(self): - check = self._check_parse_parts - # First part is anchored. - check(['c:'], ('c:', '', ['c:'])) - check(['c:/'], ('c:', '\\', ['c:\\'])) - check(['/'], ('', '\\', ['\\'])) - check(['c:a'], ('c:', '', ['c:', 'a'])) - check(['c:/a'], ('c:', '\\', ['c:\\', 'a'])) - check(['/a'], ('', '\\', ['\\', 'a'])) - # UNC paths. - check(['//a/b'], ('\\\\a\\b', '\\', ['\\\\a\\b\\'])) - check(['//a/b/'], ('\\\\a\\b', '\\', ['\\\\a\\b\\'])) - check(['//a/b/c'], ('\\\\a\\b', '\\', ['\\\\a\\b\\', 'c'])) - # Second part is anchored, so that the first part is ignored. - check(['a', 'Z:b', 'c'], ('Z:', '', ['Z:', 'b', 'c'])) - check(['a', 'Z:/b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c'])) - # UNC paths. - check(['a', '//b/c', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd'])) - # Collapsing and stripping excess slashes. - check(['a', 'Z://b//c/', 'd/'], ('Z:', '\\', ['Z:\\', 'b', 'c', 'd'])) - # UNC paths. - check(['a', '//b/c//', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd'])) - # Extended paths. - check(['//?/c:/'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\'])) - check(['//?/c:/a'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'a'])) - check(['//?/c:/a', '/b'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'b'])) - # Extended UNC paths (format is "\\?\UNC\server\share"). - check(['//?/UNC/b/c'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\'])) - check(['//?/UNC/b/c/d'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\', 'd'])) - # Second part has a root but not drive. - check(['a', '/b', 'c'], ('', '\\', ['\\', 'b', 'c'])) - check(['Z:/a', '/b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c'])) - check(['//?/Z:/a', '/b', 'c'], ('\\\\?\\Z:', '\\', ['\\\\?\\Z:\\', 'b', 'c'])) - # Joining with the same drive => the first path is appended to if - # the second path is relative. - check(['c:/a/b', 'c:x/y'], ('c:', '\\', ['c:\\', 'a', 'b', 'x', 'y'])) - check(['c:/a/b', 'c:/x/y'], ('c:', '\\', ['c:\\', 'x', 'y'])) - # Paths to files with NTFS alternate data streams - check(['./c:s'], ('', '', ['c:s'])) - check(['cc:s'], ('', '', ['cc:s'])) - check(['C:c:s'], ('C:', '', ['C:', 'c:s'])) - check(['C:/c:s'], ('C:', '\\', ['C:\\', 'c:s'])) - check(['D:a', './c:b'], ('D:', '', ['D:', 'a', 'c:b'])) - check(['D:/a', './c:b'], ('D:', '\\', ['D:\\', 'a', 'c:b'])) - - # # Tests for the pure classes. # @@ -246,6 +136,46 @@ class P(_BasePurePathSubclass, self.cls): for parent in p.parents: self.assertTrue(parent.init_called) + def _get_drive_root_parts(self, parts): + path = self.cls(*parts) + return path.drive, path.root, path.parts + + def _check_drive_root_parts(self, arg, *expected): + sep = self.flavour.sep + actual = self._get_drive_root_parts([x.replace('/', sep) for x in arg]) + self.assertEqual(actual, expected) + if altsep := self.flavour.altsep: + actual = self._get_drive_root_parts([x.replace('/', altsep) for x in arg]) + self.assertEqual(actual, expected) + + def test_drive_root_parts_common(self): + check = self._check_drive_root_parts + sep = self.flavour.sep + # Unanchored parts. + check((), '', '', ()) + check(('a',), '', '', ('a',)) + check(('a/',), '', '', ('a',)) + check(('a', 'b'), '', '', ('a', 'b')) + # Expansion. + check(('a/b',), '', '', ('a', 'b')) + check(('a/b/',), '', '', ('a', 'b')) + check(('a', 'b/c', 'd'), '', '', ('a', 'b', 'c', 'd')) + # Collapsing and stripping excess slashes. + check(('a', 'b//c', 'd'), '', '', ('a', 'b', 'c', 'd')) + check(('a', 'b/c/', 'd'), '', '', ('a', 'b', 'c', 'd')) + # Eliminating standalone dots. + check(('.',), '', '', ()) + check(('.', '.', 'b'), '', '', ('b',)) + check(('a', '.', 'b'), '', '', ('a', 'b')) + check(('a', '.', '.'), '', '', ('a',)) + # The first part is anchored. + check(('/a/b',), '', sep, (sep, 'a', 'b')) + check(('/a', 'b'), '', sep, (sep, 'a', 'b')) + check(('/a/', 'b'), '', sep, (sep, 'a', 'b')) + # Ignoring parts before an anchored part. + check(('a', '/b', 'c'), '', sep, (sep, 'b', 'c')) + check(('a', '/b', '/c'), '', sep, (sep, 'c')) + def test_join_common(self): P = self.cls p = P('a/b') @@ -770,6 +700,18 @@ def test_pickling_common(self): class PurePosixPathTest(_BasePurePathTest, unittest.TestCase): cls = pathlib.PurePosixPath + def test_drive_root_parts(self): + check = self._check_drive_root_parts + # Collapsing of excess leading slashes, except for the double-slash + # special case. + check(('//a', 'b'), '', '//', ('//', 'a', 'b')) + check(('///a', 'b'), '', '/', ('/', 'a', 'b')) + check(('////a', 'b'), '', '/', ('/', 'a', 'b')) + # Paths which look like NT paths aren't treated specially. + check(('c:a',), '', '', ('c:a',)) + check(('c:\\a',), '', '', ('c:\\a',)) + check(('\\a',), '', '', ('\\a',)) + def test_root(self): P = self.cls self.assertEqual(P('/a/b').root, '/') @@ -860,6 +802,51 @@ class PureWindowsPathTest(_BasePurePathTest, unittest.TestCase): ], }) + def test_drive_root_parts(self): + check = self._check_drive_root_parts + # First part is anchored. + check(('c:',), 'c:', '', ('c:',)) + check(('c:/',), 'c:', '\\', ('c:\\',)) + check(('/',), '', '\\', ('\\',)) + check(('c:a',), 'c:', '', ('c:', 'a')) + check(('c:/a',), 'c:', '\\', ('c:\\', 'a')) + check(('/a',), '', '\\', ('\\', 'a')) + # UNC paths. + check(('//a/b',), '\\\\a\\b', '\\', ('\\\\a\\b\\',)) + check(('//a/b/',), '\\\\a\\b', '\\', ('\\\\a\\b\\',)) + check(('//a/b/c',), '\\\\a\\b', '\\', ('\\\\a\\b\\', 'c')) + # Second part is anchored, so that the first part is ignored. + check(('a', 'Z:b', 'c'), 'Z:', '', ('Z:', 'b', 'c')) + check(('a', 'Z:/b', 'c'), 'Z:', '\\', ('Z:\\', 'b', 'c')) + # UNC paths. + check(('a', '//b/c', 'd'), '\\\\b\\c', '\\', ('\\\\b\\c\\', 'd')) + # Collapsing and stripping excess slashes. + check(('a', 'Z://b//c/', 'd/'), 'Z:', '\\', ('Z:\\', 'b', 'c', 'd')) + # UNC paths. + check(('a', '//b/c//', 'd'), '\\\\b\\c', '\\', ('\\\\b\\c\\', 'd')) + # Extended paths. + check(('//?/c:/',), '\\\\?\\c:', '\\', ('\\\\?\\c:\\',)) + check(('//?/c:/a',), '\\\\?\\c:', '\\', ('\\\\?\\c:\\', 'a')) + check(('//?/c:/a', '/b'), '\\\\?\\c:', '\\', ('\\\\?\\c:\\', 'b')) + # Extended UNC paths (format is "\\?\UNC\server\share"). + check(('//?/UNC/b/c',), '\\\\?\\UNC\\b\\c', '\\', ('\\\\?\\UNC\\b\\c\\',)) + check(('//?/UNC/b/c/d',), '\\\\?\\UNC\\b\\c', '\\', ('\\\\?\\UNC\\b\\c\\', 'd')) + # Second part has a root but not drive. + check(('a', '/b', 'c'), '', '\\', ('\\', 'b', 'c')) + check(('Z:/a', '/b', 'c'), 'Z:', '\\', ('Z:\\', 'b', 'c')) + check(('//?/Z:/a', '/b', 'c'), '\\\\?\\Z:', '\\', ('\\\\?\\Z:\\', 'b', 'c')) + # Joining with the same drive => the first path is appended to if + # the second path is relative. + check(('c:/a/b', 'c:x/y'), 'c:', '\\', ('c:\\', 'a', 'b', 'x', 'y')) + check(('c:/a/b', 'c:/x/y'), 'c:', '\\', ('c:\\', 'x', 'y')) + # Paths to files with NTFS alternate data streams + check(('./c:s',), '', '', ('c:s',)) + check(('cc:s',), '', '', ('cc:s',)) + check(('C:c:s',), 'C:', '', ('C:', 'c:s')) + check(('C:/c:s',), 'C:', '\\', ('C:\\', 'c:s')) + check(('D:a', './c:b'), 'D:', '', ('D:', 'a', 'c:b')) + check(('D:/a', './c:b'), 'D:', '\\', ('D:\\', 'a', 'c:b')) + def test_str(self): p = self.cls('a/b/c') self.assertEqual(str(p), 'a\\b\\c') From webhook-mailer at python.org Sun Apr 9 13:40:10 2023 From: webhook-mailer at python.org (barneygale) Date: Sun, 09 Apr 2023 17:40:10 -0000 Subject: [Python-checkins] GH-101362: Omit path anchor from `pathlib.PurePath()._parts` (GH-102476) Message-ID: https://github.com/python/cpython/commit/2c673d5e93cfe2779f27c4e742d7e50f7a94f356 commit: 2c673d5e93cfe2779f27c4e742d7e50f7a94f356 branch: main author: Barney Gale committer: barneygale date: 2023-04-09T18:40:03+01:00 summary: GH-101362: Omit path anchor from `pathlib.PurePath()._parts` (GH-102476) Improve performance of path construction by skipping the addition of the path anchor (`drive + root`) to the internal `_parts` list. Rename this attribute to `_tail` for clarity. files: A Misc/NEWS.d/next/Library/2023-03-06-18-49-57.gh-issue-101362.eSSy6L.rst M Lib/pathlib.py M Lib/test/test_pathlib.py diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 490f89f39d26..4ae1fae6f4b3 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -210,20 +210,17 @@ def _select_from(self, parent_path, is_dir, exists, scandir, normcase): class _PathParents(Sequence): """This object provides sequence-like access to the logical ancestors of a path. Don't try to construct it yourself.""" - __slots__ = ('_pathcls', '_drv', '_root', '_parts') + __slots__ = ('_pathcls', '_drv', '_root', '_tail') def __init__(self, path): # We don't store the instance to avoid reference cycles self._pathcls = type(path) self._drv = path.drive self._root = path.root - self._parts = path._parts + self._tail = path._tail def __len__(self): - if self._drv or self._root: - return len(self._parts) - 1 - else: - return len(self._parts) + return len(self._tail) def __getitem__(self, idx): if isinstance(idx, slice): @@ -234,7 +231,7 @@ def __getitem__(self, idx): if idx < 0: idx += len(self) return self._pathcls._from_parsed_parts(self._drv, self._root, - self._parts[:-idx - 1]) + self._tail[:-idx - 1]) def __repr__(self): return "<{}.parents>".format(self._pathcls.__name__) @@ -249,9 +246,41 @@ class PurePath(object): PureWindowsPath object. You can also instantiate either of these classes directly, regardless of your system. """ + __slots__ = ( - '_raw_path', '_drv', '_root', '_parts_cached', - '_str', '_hash', '_parts_tuple', '_parts_normcase_cached', + # The `_raw_path` slot stores an unnormalized string path. This is set + # in the `__init__()` method. + '_raw_path', + + # The `_drv`, `_root` and `_tail_cached` slots store parsed and + # normalized parts of the path. They are set when any of the `drive`, + # `root` or `_tail` properties are accessed for the first time. The + # three-part division corresponds to the result of + # `os.path.splitroot()`, except that the tail is further split on path + # separators (i.e. it is a list of strings), and that the root and + # tail are normalized. + '_drv', '_root', '_tail_cached', + + # The `_str` slot stores the string representation of the path, + # computed from the drive, root and tail when `__str__()` is called + # for the first time. It's used to implement `_str_normcase` + '_str', + + # The `_str_normcase_cached` slot stores the string path with + # normalized case. It is set when the `_str_normcase` property is + # accessed for the first time. It's used to implement `__eq__()` + # `__hash__()`, and `_parts_normcase` + '_str_normcase_cached', + + # The `_parts_normcase_cached` slot stores the case-normalized + # string path after splitting on path separators. It's set when the + # `_parts_normcase` property is accessed for the first time. It's used + # to implement comparison methods like `__lt__()`. + '_parts_normcase_cached', + + # The `_hash` slot stores the hash of the case-normalized string + # path. It's set when `__hash__()` is called for the first time. + '_hash', ) _flavour = os.path @@ -277,10 +306,7 @@ def __init__(self, *args): path = os.fspath(args[0]) else: path = self._flavour.join(*args) - if isinstance(path, str): - # Force-cast str subclasses to str (issue #21127) - path = str(path) - else: + if not isinstance(path, str): raise TypeError( "argument should be a str or an os.PathLike " "object where __fspath__ returns a str, " @@ -299,33 +325,32 @@ def _parse_path(cls, path): if drv.startswith(sep): # pathlib assumes that UNC paths always have a root. root = sep - unfiltered_parsed = [drv + root] + rel.split(sep) - parsed = [sys.intern(x) for x in unfiltered_parsed if x and x != '.'] + parsed = [sys.intern(str(x)) for x in rel.split(sep) if x and x != '.'] return drv, root, parsed def _load_parts(self): - drv, root, parts = self._parse_path(self._raw_path) + drv, root, tail = self._parse_path(self._raw_path) self._drv = drv self._root = root - self._parts_cached = parts + self._tail_cached = tail @classmethod - def _from_parsed_parts(cls, drv, root, parts): - path = cls._format_parsed_parts(drv, root, parts) + def _from_parsed_parts(cls, drv, root, tail): + path = cls._format_parsed_parts(drv, root, tail) self = cls(path) self._str = path or '.' self._drv = drv self._root = root - self._parts_cached = parts + self._tail_cached = tail return self @classmethod - def _format_parsed_parts(cls, drv, root, parts): + def _format_parsed_parts(cls, drv, root, tail): if drv or root: - return drv + root + cls._flavour.sep.join(parts[1:]) - elif parts and cls._flavour.splitdrive(parts[0])[0]: - parts = ['.'] + parts - return cls._flavour.sep.join(parts) + return drv + root + cls._flavour.sep.join(tail) + elif tail and cls._flavour.splitdrive(tail[0])[0]: + tail = ['.'] + tail + return cls._flavour.sep.join(tail) def __str__(self): """Return the string representation of the path, suitable for @@ -334,7 +359,7 @@ def __str__(self): return self._str except AttributeError: self._str = self._format_parsed_parts(self.drive, self.root, - self._parts) or '.' + self._tail) or '.' return self._str def __fspath__(self): @@ -374,25 +399,34 @@ def as_uri(self): path = str(self) return prefix + urlquote_from_bytes(os.fsencode(path)) + @property + def _str_normcase(self): + # String with normalized case, for hashing and equality checks + try: + return self._str_normcase_cached + except AttributeError: + self._str_normcase_cached = self._flavour.normcase(str(self)) + return self._str_normcase_cached + @property def _parts_normcase(self): - # Cached parts with normalized case, for hashing and comparison. + # Cached parts with normalized case, for comparisons. try: return self._parts_normcase_cached except AttributeError: - self._parts_normcase_cached = [self._flavour.normcase(p) for p in self._parts] + self._parts_normcase_cached = self._str_normcase.split(self._flavour.sep) return self._parts_normcase_cached def __eq__(self, other): if not isinstance(other, PurePath): return NotImplemented - return self._parts_normcase == other._parts_normcase and self._flavour is other._flavour + return self._str_normcase == other._str_normcase and self._flavour is other._flavour def __hash__(self): try: return self._hash except AttributeError: - self._hash = hash(tuple(self._parts_normcase)) + self._hash = hash(self._str_normcase) return self._hash def __lt__(self, other): @@ -434,12 +468,12 @@ def root(self): return self._root @property - def _parts(self): + def _tail(self): try: - return self._parts_cached + return self._tail_cached except AttributeError: self._load_parts() - return self._parts_cached + return self._tail_cached @property def anchor(self): @@ -450,10 +484,10 @@ def anchor(self): @property def name(self): """The final path component, if any.""" - parts = self._parts - if len(parts) == (1 if (self.drive or self.root) else 0): + tail = self._tail + if not tail: return '' - return parts[-1] + return tail[-1] @property def suffix(self): @@ -501,7 +535,7 @@ def with_name(self, name): if drv or root or not tail or f.sep in tail or (f.altsep and f.altsep in tail): raise ValueError("Invalid name %r" % (name)) return self._from_parsed_parts(self.drive, self.root, - self._parts[:-1] + [name]) + self._tail[:-1] + [name]) def with_stem(self, stem): """Return a new path with the stem changed.""" @@ -526,7 +560,7 @@ def with_suffix(self, suffix): else: name = name[:-len(old_suffix)] + suffix return self._from_parsed_parts(self.drive, self.root, - self._parts[:-1] + [name]) + self._tail[:-1] + [name]) def relative_to(self, other, /, *_deprecated, walk_up=False): """Return the relative path to another path identified by the passed @@ -551,7 +585,7 @@ def relative_to(self, other, /, *_deprecated, walk_up=False): raise ValueError(f"{str(self)!r} and {str(other)!r} have different anchors") if step and not walk_up: raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}") - parts = ('..',) * step + self.parts[len(path.parts):] + parts = ['..'] * step + self._tail[len(path._tail):] return path_cls(*parts) def is_relative_to(self, other, /, *_deprecated): @@ -570,13 +604,10 @@ def is_relative_to(self, other, /, *_deprecated): def parts(self): """An object providing sequence-like access to the components in the filesystem path.""" - # We cache the tuple to avoid building a new one each time .parts - # is accessed. XXX is this necessary? - try: - return self._parts_tuple - except AttributeError: - self._parts_tuple = tuple(self._parts) - return self._parts_tuple + if self.drive or self.root: + return (self.drive + self.root,) + tuple(self._tail) + else: + return tuple(self._tail) def joinpath(self, *args): """Combine this path with one or several arguments, and return a @@ -603,10 +634,10 @@ def parent(self): """The logical parent of the path.""" drv = self.drive root = self.root - parts = self._parts - if len(parts) == 1 and (drv or root): + tail = self._tail + if not tail: return self - return self._from_parsed_parts(drv, root, parts[:-1]) + return self._from_parsed_parts(drv, root, tail[:-1]) @property def parents(self): @@ -624,29 +655,29 @@ def is_absolute(self): def is_reserved(self): """Return True if the path contains one of the special names reserved by the system, if any.""" - if self._flavour is posixpath or not self._parts: + if self._flavour is posixpath or not self._tail: return False # NOTE: the rules for reserved names seem somewhat complicated # (e.g. r"..\NUL" is reserved but not r"foo\NUL" if "foo" does not # exist). We err on the side of caution and return True for paths # which are not considered reserved by Windows. - if self._parts[0].startswith('\\\\'): + if self.drive.startswith('\\\\'): # UNC paths are never reserved. return False - name = self._parts[-1].partition('.')[0].partition(':')[0].rstrip(' ') + name = self._tail[-1].partition('.')[0].partition(':')[0].rstrip(' ') return name.upper() in _WIN_RESERVED_NAMES def match(self, path_pattern): """ Return True if this path matches the given pattern. """ - path_pattern = self._flavour.normcase(path_pattern) - drv, root, pat_parts = self._parse_path(path_pattern) - if not pat_parts: + pat = type(self)(path_pattern) + if not pat.parts: raise ValueError("empty pattern") + pat_parts = pat._parts_normcase parts = self._parts_normcase - if drv or root: + if pat.drive or pat.root: if len(pat_parts) != len(parts): return False elif len(pat_parts) > len(parts): @@ -707,11 +738,21 @@ def __new__(cls, *args, **kwargs): cls = WindowsPath if os.name == 'nt' else PosixPath return object.__new__(cls) - def _make_child_relpath(self, part): - # This is an optimization used for dir walking. `part` must be - # a single part relative to this path. - parts = self._parts + [part] - return self._from_parsed_parts(self.drive, self.root, parts) + def _make_child_relpath(self, name): + path_str = str(self) + tail = self._tail + if tail: + path_str = f'{path_str}{self._flavour.sep}{name}' + elif path_str != '.': + path_str = f'{path_str}{name}' + else: + path_str = name + path = type(self)(path_str) + path._str = path_str + path._drv = self.drive + path._root = self.root + path._tail_cached = tail + [name] + return path def __enter__(self): # In previous versions of pathlib, __exit__() marked this path as @@ -1196,12 +1237,12 @@ def expanduser(self): (as returned by os.path.expanduser) """ if (not (self.drive or self.root) and - self._parts and self._parts[0][:1] == '~'): - homedir = self._flavour.expanduser(self._parts[0]) + self._tail and self._tail[0][:1] == '~'): + homedir = self._flavour.expanduser(self._tail[0]) if homedir[:1] == "~": raise RuntimeError("Could not determine home directory.") - drv, root, parts = self._parse_path(homedir) - return self._from_parsed_parts(drv, root, parts + self._parts[1:]) + drv, root, tail = self._parse_path(homedir) + return self._from_parsed_parts(drv, root, tail + self._tail[1:]) return self diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index fe75f1c2580b..3c6da94d0946 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -346,8 +346,6 @@ def test_parts_common(self): p = P('a/b') parts = p.parts self.assertEqual(parts, ('a', 'b')) - # The object gets reused. - self.assertIs(parts, p.parts) # When the path is absolute, the anchor is a separate part. p = P('/a/b') parts = p.parts diff --git a/Misc/NEWS.d/next/Library/2023-03-06-18-49-57.gh-issue-101362.eSSy6L.rst b/Misc/NEWS.d/next/Library/2023-03-06-18-49-57.gh-issue-101362.eSSy6L.rst new file mode 100644 index 000000000000..87617a503c0d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-06-18-49-57.gh-issue-101362.eSSy6L.rst @@ -0,0 +1,2 @@ +Speed up :class:`pathlib.Path` construction by omitting the path anchor from +the internal list of path parts. From webhook-mailer at python.org Sun Apr 9 15:17:47 2023 From: webhook-mailer at python.org (rhettinger) Date: Sun, 09 Apr 2023 19:17:47 -0000 Subject: [Python-checkins] Itertool recipe improvements (GH-103399) Message-ID: https://github.com/python/cpython/commit/f65fdbb8fdc16d6b1eddaecc92d0dfa131761090 commit: f65fdbb8fdc16d6b1eddaecc92d0dfa131761090 branch: main author: Raymond Hettinger committer: rhettinger date: 2023-04-09T14:17:37-05:00 summary: Itertool recipe improvements (GH-103399) files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 70e5b7905f20..e57c393a6b37 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -769,8 +769,8 @@ well as with the built-in itertools such as ``map()``, ``filter()``, A secondary purpose of the recipes is to serve as an incubator. The ``accumulate()``, ``compress()``, and ``pairwise()`` itertools started out as -recipes. Currently, the ``iter_index()`` recipe is being tested to see -whether it proves its worth. +recipes. Currently, the ``sliding_window()`` and ``iter_index()`` recipes +are being tested to see whether they prove their worth. Substantially all of these recipes and many, many others can be installed from the `more-itertools project `_ found @@ -806,6 +806,23 @@ which incur interpreter overhead. "Return function(0), function(1), ..." return map(function, count(start)) + def repeatfunc(func, times=None, *args): + """Repeat calls to func with specified arguments. + + Example: repeatfunc(random.random) + """ + if times is None: + return starmap(func, repeat(args)) + return starmap(func, repeat(args, times)) + + def flatten(list_of_lists): + "Flatten one level of nesting" + return chain.from_iterable(list_of_lists) + + def ncycles(iterable, n): + "Returns the sequence elements n times" + return chain.from_iterable(repeat(tuple(iterable), n)) + def tail(n, iterable): "Return an iterator over the last n items" # tail(3, 'ABCDEFG') --> E F G @@ -825,70 +842,27 @@ which incur interpreter overhead. "Returns the nth item or a default value" return next(islice(iterable, n, None), default) - def all_equal(iterable): - "Returns True if all the elements are equal to each other" - g = groupby(iterable) - return next(g, True) and not next(g, False) - def quantify(iterable, pred=bool): "Count how many times the predicate is True" return sum(map(pred, iterable)) - def ncycles(iterable, n): - "Returns the sequence elements n times" - return chain.from_iterable(repeat(tuple(iterable), n)) - - def sum_of_squares(it): - "Add up the squares of the input values." - # sum_of_squares([10, 20, 30]) -> 1400 - return math.sumprod(*tee(it)) - - def transpose(it): - "Swap the rows and columns of the input." - # transpose([(1, 2, 3), (11, 22, 33)]) --> (1, 11) (2, 22) (3, 33) - return zip(*it, strict=True) - - def matmul(m1, m2): - "Multiply two matrices." - # matmul([(7, 5), (3, 5)], [[2, 5], [7, 9]]) --> (49, 80), (41, 60) - n = len(m2[0]) - return batched(starmap(math.sumprod, product(m1, transpose(m2))), n) - - def convolve(signal, kernel): - # See: https://betterexplained.com/articles/intuitive-convolution/ - # convolve(data, [0.25, 0.25, 0.25, 0.25]) --> Moving average (blur) - # convolve(data, [1, -1]) --> 1st finite difference (1st derivative) - # convolve(data, [1, -2, 1]) --> 2nd finite difference (2nd derivative) - kernel = tuple(kernel)[::-1] - n = len(kernel) - window = collections.deque([0], maxlen=n) * n - for x in chain(signal, repeat(0, n-1)): - window.append(x) - yield math.sumprod(kernel, window) + def all_equal(iterable): + "Returns True if all the elements are equal to each other" + g = groupby(iterable) + return next(g, True) and not next(g, False) - def polynomial_from_roots(roots): - """Compute a polynomial's coefficients from its roots. + def first_true(iterable, default=False, pred=None): + """Returns the first true value in the iterable. - (x - 5) (x + 4) (x - 3) expands to: x? -4x? -17x + 60 - """ - # polynomial_from_roots([5, -4, 3]) --> [1, -4, -17, 60] - expansion = [1] - for r in roots: - expansion = convolve(expansion, (1, -r)) - return list(expansion) + If no true value is found, returns *default* - def polynomial_eval(coefficients, x): - """Evaluate a polynomial at a specific value. + If *pred* is not None, returns the first item + for which pred(item) is true. - Computes with better numeric stability than Horner's method. """ - # Evaluate x? -4x? -17x + 60 at x = 2.5 - # polynomial_eval([1, -4, -17, 60], x=2.5) --> 8.125 - n = len(coefficients) - if n == 0: - return x * 0 # coerce zero to the type of x - powers = map(pow, repeat(x), reversed(range(n))) - return math.sumprod(coefficients, powers) + # first_true([a,b,c], x) --> a or b or c or x + # first_true([a,b], x, f) --> a if f(a) else b if f(b) else x + return next(filter(pred, iterable), default) def iter_index(iterable, value, start=0): "Return indices where a value occurs in a sequence or iterable." @@ -913,44 +887,28 @@ which incur interpreter overhead. except ValueError: pass - def sieve(n): - "Primes less than n" - # sieve(30) --> 2 3 5 7 11 13 17 19 23 29 - data = bytearray((0, 1)) * (n // 2) - data[:3] = 0, 0, 0 - limit = math.isqrt(n) + 1 - for p in compress(range(limit), data): - data[p*p : n : p+p] = bytes(len(range(p*p, n, p+p))) - data[2] = 1 - return iter_index(data, 1) if n > 2 else iter([]) - - def factor(n): - "Prime factors of n." - # factor(99) --> 3 3 11 - for prime in sieve(math.isqrt(n) + 1): - while True: - quotient, remainder = divmod(n, prime) - if remainder: - break - yield prime - n = quotient - if n == 1: - return - if n > 1: - yield n + def iter_except(func, exception, first=None): + """ Call a function repeatedly until an exception is raised. - def flatten(list_of_lists): - "Flatten one level of nesting" - return chain.from_iterable(list_of_lists) + Converts a call-until-exception interface to an iterator interface. + Like builtins.iter(func, sentinel) but uses an exception instead + of a sentinel to end the loop. - def repeatfunc(func, times=None, *args): - """Repeat calls to func with specified arguments. + Examples: + iter_except(functools.partial(heappop, h), IndexError) # priority queue iterator + iter_except(d.popitem, KeyError) # non-blocking dict iterator + iter_except(d.popleft, IndexError) # non-blocking deque iterator + iter_except(q.get_nowait, Queue.Empty) # loop over a producer Queue + iter_except(s.pop, KeyError) # non-blocking set iterator - Example: repeatfunc(random.random) """ - if times is None: - return starmap(func, repeat(args)) - return starmap(func, repeat(args, times)) + try: + if first is not None: + yield first() # For database APIs needing an initial cast to db.first() + while True: + yield func() + except exception: + pass def grouper(iterable, n, *, incomplete='fill', fillvalue=None): "Collect data into non-overlapping fixed-length chunks or blocks" @@ -967,12 +925,6 @@ which incur interpreter overhead. else: raise ValueError('Expected fill, strict, or ignore') - def triplewise(iterable): - "Return overlapping triplets from an iterable" - # triplewise('ABCDEFG') --> ABC BCD CDE DEF EFG - for (a, _), (b, c) in pairwise(pairwise(iterable)): - yield a, b, c - def sliding_window(iterable, n): # sliding_window('ABCDEFG', 4) --> ABCD BCDE CDEF DEFG it = iter(iterable) @@ -1003,6 +955,12 @@ which incur interpreter overhead. t1, t2 = tee(iterable) return filterfalse(pred, t1), filter(pred, t2) + def subslices(seq): + "Return all contiguous non-empty subslices of a sequence" + # subslices('ABCD') --> A AB ABC ABCD B BC BCD C CD D + slices = starmap(slice, combinations(range(len(seq) + 1), 2)) + return map(operator.getitem, repeat(seq), slices) + def before_and_after(predicate, it): """ Variant of takewhile() that allows complete access to the remainder of the iterator. @@ -1032,17 +990,6 @@ which incur interpreter overhead. yield from it return true_iterator(), remainder_iterator() - def subslices(seq): - "Return all contiguous non-empty subslices of a sequence" - # subslices('ABCD') --> A AB ABC ABCD B BC BCD C CD D - slices = starmap(slice, combinations(range(len(seq) + 1), 2)) - return map(operator.getitem, repeat(seq), slices) - - def powerset(iterable): - "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)" - s = list(iterable) - return chain.from_iterable(combinations(s, r) for r in range(len(s)+1)) - def unique_everseen(iterable, key=None): "List unique elements, preserving order. Remember all elements ever seen." # unique_everseen('AAAABBBCCDAABBB') --> A B C D @@ -1072,41 +1019,96 @@ which incur interpreter overhead. # unique_justseen('ABBcCAD', str.lower) --> A B c A D return map(next, map(operator.itemgetter(1), groupby(iterable, key))) - def iter_except(func, exception, first=None): - """ Call a function repeatedly until an exception is raised. - Converts a call-until-exception interface to an iterator interface. - Like builtins.iter(func, sentinel) but uses an exception instead - of a sentinel to end the loop. +The following recipes have a more mathematical flavor: - Examples: - iter_except(functools.partial(heappop, h), IndexError) # priority queue iterator - iter_except(d.popitem, KeyError) # non-blocking dict iterator - iter_except(d.popleft, IndexError) # non-blocking deque iterator - iter_except(q.get_nowait, Queue.Empty) # loop over a producer Queue - iter_except(s.pop, KeyError) # non-blocking set iterator +.. testcode:: - """ - try: - if first is not None: - yield first() # For database APIs needing an initial cast to db.first() + def powerset(iterable): + "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)" + s = list(iterable) + return chain.from_iterable(combinations(s, r) for r in range(len(s)+1)) + + def sieve(n): + "Primes less than n" + # sieve(30) --> 2 3 5 7 11 13 17 19 23 29 + data = bytearray((0, 1)) * (n // 2) + data[:3] = 0, 0, 0 + limit = math.isqrt(n) + 1 + for p in compress(range(limit), data): + data[p*p : n : p+p] = bytes(len(range(p*p, n, p+p))) + data[2] = 1 + return iter_index(data, 1) if n > 2 else iter([]) + + def factor(n): + "Prime factors of n." + # factor(99) --> 3 3 11 + for prime in sieve(math.isqrt(n) + 1): while True: - yield func() - except exception: - pass + quotient, remainder = divmod(n, prime) + if remainder: + break + yield prime + n = quotient + if n == 1: + return + if n > 1: + yield n - def first_true(iterable, default=False, pred=None): - """Returns the first true value in the iterable. + def sum_of_squares(it): + "Add up the squares of the input values." + # sum_of_squares([10, 20, 30]) -> 1400 + return math.sumprod(*tee(it)) - If no true value is found, returns *default* + def transpose(it): + "Swap the rows and columns of the input." + # transpose([(1, 2, 3), (11, 22, 33)]) --> (1, 11) (2, 22) (3, 33) + return zip(*it, strict=True) - If *pred* is not None, returns the first item - for which pred(item) is true. + def matmul(m1, m2): + "Multiply two matrices." + # matmul([(7, 5), (3, 5)], [[2, 5], [7, 9]]) --> (49, 80), (41, 60) + n = len(m2[0]) + return batched(starmap(math.sumprod, product(m1, transpose(m2))), n) + + def convolve(signal, kernel): + """Linear convolution of two iterables. + Article: https://betterexplained.com/articles/intuitive-convolution/ + Video: https://www.youtube.com/watch?v=KuXjwB4LzSA """ - # first_true([a,b,c], x) --> a or b or c or x - # first_true([a,b], x, f) --> a if f(a) else b if f(b) else x - return next(filter(pred, iterable), default) + # convolve(data, [0.25, 0.25, 0.25, 0.25]) --> Moving average (blur) + # convolve(data, [1, -1]) --> 1st finite difference (1st derivative) + # convolve(data, [1, -2, 1]) --> 2nd finite difference (2nd derivative) + kernel = tuple(kernel)[::-1] + n = len(kernel) + padded_signal = chain(repeat(0, n-1), signal, [0] * (n-1)) + for window in sliding_window(padded_signal, n): + yield math.sumprod(kernel, window) + + def polynomial_from_roots(roots): + """Compute a polynomial's coefficients from its roots. + + (x - 5) (x + 4) (x - 3) expands to: x? -4x? -17x + 60 + """ + # polynomial_from_roots([5, -4, 3]) --> [1, -4, -17, 60] + expansion = [1] + for r in roots: + expansion = convolve(expansion, (1, -r)) + return list(expansion) + + def polynomial_eval(coefficients, x): + """Evaluate a polynomial at a specific value. + + Computes with better numeric stability than Horner's method. + """ + # Evaluate x? -4x? -17x + 60 at x = 2.5 + # polynomial_eval([1, -4, -17, 60], x=2.5) --> 8.125 + n = len(coefficients) + if n == 0: + return x * 0 # coerce zero to the type of x + powers = map(pow, repeat(x), reversed(range(n))) + return math.sumprod(coefficients, powers) def nth_combination(iterable, r, index): "Equivalent to list(combinations(iterable, r))[index]" @@ -1126,6 +1128,7 @@ which incur interpreter overhead. result.append(pool[-1-n]) return tuple(result) + .. doctest:: :hide: @@ -1401,9 +1404,6 @@ which incur interpreter overhead. >>> list(grouper('abcdefg', n=3, incomplete='ignore')) [('a', 'b', 'c'), ('d', 'e', 'f')] - >>> list(triplewise('ABCDEFG')) - [('A', 'B', 'C'), ('B', 'C', 'D'), ('C', 'D', 'E'), ('D', 'E', 'F'), ('E', 'F', 'G')] - >>> list(sliding_window('ABCDEFG', 4)) [('A', 'B', 'C', 'D'), ('B', 'C', 'D', 'E'), ('C', 'D', 'E', 'F'), ('D', 'E', 'F', 'G')] @@ -1485,3 +1485,45 @@ which incur interpreter overhead. >>> combos = list(combinations(iterable, r)) >>> all(nth_combination(iterable, r, i) == comb for i, comb in enumerate(combos)) True + + +.. testcode:: + :hide: + + # Old recipes and their tests which are guaranteed to continue to work. + + def sumprod(vec1, vec2): + "Compute a sum of products." + return sum(starmap(operator.mul, zip(vec1, vec2, strict=True))) + + def dotproduct(vec1, vec2): + return sum(map(operator.mul, vec1, vec2)) + + def pad_none(iterable): + """Returns the sequence elements and then returns None indefinitely. + + Useful for emulating the behavior of the built-in map() function. + """ + return chain(iterable, repeat(None)) + + def triplewise(iterable): + "Return overlapping triplets from an iterable" + # triplewise('ABCDEFG') --> ABC BCD CDE DEF EFG + for (a, _), (b, c) in pairwise(pairwise(iterable)): + yield a, b, c + + +.. doctest:: + :hide: + + >>> dotproduct([1,2,3], [4,5,6]) + 32 + + >>> sumprod([1,2,3], [4,5,6]) + 32 + + >>> list(islice(pad_none('abc'), 0, 6)) + ['a', 'b', 'c', None, None, None] + + >>> list(triplewise('ABCDEFG')) + [('A', 'B', 'C'), ('B', 'C', 'D'), ('C', 'D', 'E'), ('D', 'E', 'F'), ('E', 'F', 'G')] From webhook-mailer at python.org Sun Apr 9 16:00:29 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Sun, 09 Apr 2023 20:00:29 -0000 Subject: [Python-checkins] gh-83004: Harden winsound init (#103385) Message-ID: https://github.com/python/cpython/commit/6d97e521169b07851cbbf7fccbf9bef3f41e3ce0 commit: 6d97e521169b07851cbbf7fccbf9bef3f41e3ce0 branch: main author: Erlend E. Aasland committer: erlend-aasland date: 2023-04-09T22:00:22+02:00 summary: gh-83004: Harden winsound init (#103385) files: M PC/winsound.c diff --git a/PC/winsound.c b/PC/winsound.c index 65025ddc5e1f..bae8e4497957 100644 --- a/PC/winsound.c +++ b/PC/winsound.c @@ -202,19 +202,11 @@ static struct PyMethodDef sound_methods[] = {NULL, NULL} }; -static void -add_define(PyObject *dict, const char *key, long value) -{ - PyObject *k = PyUnicode_FromString(key); - PyObject *v = PyLong_FromLong(value); - if (v && k) { - PyDict_SetItem(dict, k, v); - } - Py_XDECREF(k); - Py_XDECREF(v); -} - -#define ADD_DEFINE(tok) add_define(dict,#tok,tok) +#define ADD_DEFINE(CONST) do { \ + if (PyModule_AddIntConstant(module, #CONST, CONST) < 0) { \ + goto error; \ + } \ +} while (0) static struct PyModuleDef winsoundmodule = { @@ -232,11 +224,10 @@ static struct PyModuleDef winsoundmodule = { PyMODINIT_FUNC PyInit_winsound(void) { - PyObject *dict; PyObject *module = PyModule_Create(&winsoundmodule); - if (module == NULL) + if (module == NULL) { return NULL; - dict = PyModule_GetDict(module); + } ADD_DEFINE(SND_ASYNC); ADD_DEFINE(SND_NODEFAULT); @@ -254,5 +245,12 @@ PyInit_winsound(void) ADD_DEFINE(MB_ICONEXCLAMATION); ADD_DEFINE(MB_ICONHAND); ADD_DEFINE(MB_ICONQUESTION); + +#undef ADD_DEFINE + return module; + +error: + Py_DECREF(module); + return NULL; } From webhook-mailer at python.org Sun Apr 9 17:55:39 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sun, 09 Apr 2023 21:55:39 -0000 Subject: [Python-checkins] Fix old behaviour in typing documentation (#103400) Message-ID: https://github.com/python/cpython/commit/ecad802e3f9ef7063e7d7fe9f0c037561396ef8e commit: ecad802e3f9ef7063e7d7fe9f0c037561396ef8e branch: main author: James Hilton-Balfe committer: AlexWaygood date: 2023-04-09T22:55:32+01:00 summary: Fix old behaviour in typing documentation (#103400) files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 03ff259bbdf7..15bab7775ead 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -423,7 +423,7 @@ to this is that a list of types can be used to substitute a :class:`ParamSpec`:: >>> class Z(Generic[T, P]): ... ... >>> Z[int, [dict, float]] - __main__.Z[int, (, )] + __main__.Z[int, [dict, float]] Furthermore, a generic with only one parameter specification variable will accept @@ -434,9 +434,9 @@ to the former, so the following are equivalent:: >>> class X(Generic[P]): ... ... >>> X[int, str] - __main__.X[(, )] + __main__.X[[int, str]] >>> X[[int, str]] - __main__.X[(, )] + __main__.X[[int, str]] Do note that generics with :class:`ParamSpec` may not have correct ``__parameters__`` after substitution in some cases because they From webhook-mailer at python.org Sun Apr 9 20:14:18 2023 From: webhook-mailer at python.org (ned-deily) Date: Mon, 10 Apr 2023 00:14:18 -0000 Subject: [Python-checkins] [3.7] GH-102306 Avoid GHA CI macOS test_posix failure by using the appropriate macOS SDK. (GH-102427) Message-ID: https://github.com/python/cpython/commit/7522ff72484fab740a85f27f2326336906a69674 commit: 7522ff72484fab740a85f27f2326336906a69674 branch: 3.7 author: Ned Deily committer: ned-deily date: 2023-04-09T20:13:44-04:00 summary: [3.7] GH-102306 Avoid GHA CI macOS test_posix failure by using the appropriate macOS SDK. (GH-102427) Co-authored-by: Oleg Iarygin files: A Misc/NEWS.d/next/Build/2023-02-27-18-55-32.gh-issue-102306.bkokFL.rst M .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a1f63747aa2a..149436319673 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -128,7 +128,7 @@ jobs: steps: - uses: actions/checkout at v2 - name: Configure CPython - run: ./configure --with-pydebug --with-openssl=/usr/local/opt/openssl --prefix=/opt/python-dev + run: SDKROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX12.sdk ./configure --with-pydebug --with-openssl=/usr/local/opt/openssl --prefix=/opt/python-dev - name: Build CPython run: make -j4 - name: Display build info diff --git a/Misc/NEWS.d/next/Build/2023-02-27-18-55-32.gh-issue-102306.bkokFL.rst b/Misc/NEWS.d/next/Build/2023-02-27-18-55-32.gh-issue-102306.bkokFL.rst new file mode 100644 index 000000000000..ba331a06bec4 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-02-27-18-55-32.gh-issue-102306.bkokFL.rst @@ -0,0 +1 @@ +Avoid GHA CI macOS test_posix failure by using the appropriate macOS SDK. From webhook-mailer at python.org Mon Apr 10 07:09:29 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Mon, 10 Apr 2023 11:09:29 -0000 Subject: [Python-checkins] gh-103395: Improve `typing._GenericAlias.__dir__` coverage (#103396) Message-ID: https://github.com/python/cpython/commit/a28e2ce3fbcc852959324879e0bbf5ba8ecf0105 commit: a28e2ce3fbcc852959324879e0bbf5ba8ecf0105 branch: main author: Nikita Sobolev committer: AlexWaygood date: 2023-04-10T12:09:19+01:00 summary: gh-103395: Improve `typing._GenericAlias.__dir__` coverage (#103396) files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index b8eee9a570a3..f983efe956f9 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -855,6 +855,14 @@ def test_accepts_single_type(self): (*tuple[int],) Unpack[Tuple[int]] + def test_dir(self): + dir_items = set(dir(Unpack[Tuple[int]])) + for required_item in [ + '__args__', '__parameters__', '__origin__', + ]: + with self.subTest(required_item=required_item): + self.assertIn(required_item, dir_items) + def test_rejects_multiple_types(self): with self.assertRaises(TypeError): Unpack[Tuple[int], Tuple[str]] @@ -1699,6 +1707,14 @@ def test_repr(self): u = Optional[str] self.assertEqual(repr(u), 'typing.Optional[str]') + def test_dir(self): + dir_items = set(dir(Union[str, int])) + for required_item in [ + '__args__', '__parameters__', '__origin__', + ]: + with self.subTest(required_item=required_item): + self.assertIn(required_item, dir_items) + def test_cannot_subclass(self): with self.assertRaisesRegex(TypeError, r'Cannot subclass typing\.Union'): @@ -1839,6 +1855,15 @@ def test_eq_hash(self): self.assertNotEqual(C, Callable[..., int]) self.assertNotEqual(C, Callable) + def test_dir(self): + Callable = self.Callable + dir_items = set(dir(Callable[..., int])) + for required_item in [ + '__args__', '__parameters__', '__origin__', + ]: + with self.subTest(required_item=required_item): + self.assertIn(required_item, dir_items) + def test_cannot_instantiate(self): Callable = self.Callable with self.assertRaises(TypeError): @@ -2151,6 +2176,14 @@ def test_repr(self): self.assertEqual(repr(Literal[None]), "typing.Literal[None]") self.assertEqual(repr(Literal[1, 2, 3, 3]), "typing.Literal[1, 2, 3]") + def test_dir(self): + dir_items = set(dir(Literal[1, 2, 3])) + for required_item in [ + '__args__', '__parameters__', '__origin__', + ]: + with self.subTest(required_item=required_item): + self.assertIn(required_item, dir_items) + def test_cannot_init(self): with self.assertRaises(TypeError): Literal() @@ -7315,6 +7348,15 @@ def test_repr(self): "typing.Annotated[typing.List[int], 4, 5]" ) + def test_dir(self): + dir_items = set(dir(Annotated[int, 4])) + for required_item in [ + '__args__', '__parameters__', '__origin__', + '__metadata__', + ]: + with self.subTest(required_item=required_item): + self.assertIn(required_item, dir_items) + def test_flatten(self): A = Annotated[Annotated[int, 4], 5] self.assertEqual(A, Annotated[int, 4, 5]) @@ -8033,6 +8075,15 @@ class MyClass: ... c = Concatenate[MyClass, P] self.assertNotEqual(c, Concatenate) + def test_dir(self): + P = ParamSpec('P') + dir_items = set(dir(Concatenate[int, P])) + for required_item in [ + '__args__', '__parameters__', '__origin__', + ]: + with self.subTest(required_item=required_item): + self.assertIn(required_item, dir_items) + def test_valid_uses(self): P = ParamSpec('P') T = TypeVar('T') @@ -8310,10 +8361,18 @@ class Foo(Generic[T]): def bar(self): pass baz = 3 + __magic__ = 4 + # The class attributes of the original class should be visible even # in dir() of the GenericAlias. See bpo-45755. - self.assertIn('bar', dir(Foo[int])) - self.assertIn('baz', dir(Foo[int])) + dir_items = set(dir(Foo[int])) + for required_item in [ + 'bar', 'baz', + '__args__', '__parameters__', '__origin__', + ]: + with self.subTest(required_item=required_item): + self.assertIn(required_item, dir_items) + self.assertNotIn('__magic__', dir_items) class RevealTypeTests(BaseTestCase): From webhook-mailer at python.org Mon Apr 10 07:38:15 2023 From: webhook-mailer at python.org (miss-islington) Date: Mon, 10 Apr 2023 11:38:15 -0000 Subject: [Python-checkins] gh-103395: Improve `typing._GenericAlias.__dir__` coverage (GH-103396) Message-ID: https://github.com/python/cpython/commit/4e284ffa2e56dfab4f5cde83b1679c9a51206e9a commit: 4e284ffa2e56dfab4f5cde83b1679c9a51206e9a branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-10T04:37:40-07:00 summary: gh-103395: Improve `typing._GenericAlias.__dir__` coverage (GH-103396) (cherry picked from commit a28e2ce3fbcc852959324879e0bbf5ba8ecf0105) Co-authored-by: Nikita Sobolev files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 46cff6ad5085..be804f1699a0 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -851,6 +851,14 @@ def test_accepts_single_type(self): (*tuple[int],) Unpack[Tuple[int]] + def test_dir(self): + dir_items = set(dir(Unpack[Tuple[int]])) + for required_item in [ + '__args__', '__parameters__', '__origin__', + ]: + with self.subTest(required_item=required_item): + self.assertIn(required_item, dir_items) + def test_rejects_multiple_types(self): with self.assertRaises(TypeError): Unpack[Tuple[int], Tuple[str]] @@ -1696,6 +1704,14 @@ def test_repr(self): u = Optional[str] self.assertEqual(repr(u), 'typing.Optional[str]') + def test_dir(self): + dir_items = set(dir(Union[str, int])) + for required_item in [ + '__args__', '__parameters__', '__origin__', + ]: + with self.subTest(required_item=required_item): + self.assertIn(required_item, dir_items) + def test_cannot_subclass(self): with self.assertRaises(TypeError): class C(Union): @@ -1834,6 +1850,15 @@ def test_eq_hash(self): self.assertNotEqual(C, Callable[..., int]) self.assertNotEqual(C, Callable) + def test_dir(self): + Callable = self.Callable + dir_items = set(dir(Callable[..., int])) + for required_item in [ + '__args__', '__parameters__', '__origin__', + ]: + with self.subTest(required_item=required_item): + self.assertIn(required_item, dir_items) + def test_cannot_instantiate(self): Callable = self.Callable with self.assertRaises(TypeError): @@ -2146,6 +2171,14 @@ def test_repr(self): self.assertEqual(repr(Literal[None]), "typing.Literal[None]") self.assertEqual(repr(Literal[1, 2, 3, 3]), "typing.Literal[1, 2, 3]") + def test_dir(self): + dir_items = set(dir(Literal[1, 2, 3])) + for required_item in [ + '__args__', '__parameters__', '__origin__', + ]: + with self.subTest(required_item=required_item): + self.assertIn(required_item, dir_items) + def test_cannot_init(self): with self.assertRaises(TypeError): Literal() @@ -7002,6 +7035,15 @@ def test_repr(self): "typing.Annotated[typing.List[int], 4, 5]" ) + def test_dir(self): + dir_items = set(dir(Annotated[int, 4])) + for required_item in [ + '__args__', '__parameters__', '__origin__', + '__metadata__', + ]: + with self.subTest(required_item=required_item): + self.assertIn(required_item, dir_items) + def test_flatten(self): A = Annotated[Annotated[int, 4], 5] self.assertEqual(A, Annotated[int, 4, 5]) @@ -7701,6 +7743,15 @@ class MyClass: ... c = Concatenate[MyClass, P] self.assertNotEqual(c, Concatenate) + def test_dir(self): + P = ParamSpec('P') + dir_items = set(dir(Concatenate[int, P])) + for required_item in [ + '__args__', '__parameters__', '__origin__', + ]: + with self.subTest(required_item=required_item): + self.assertIn(required_item, dir_items) + def test_valid_uses(self): P = ParamSpec('P') T = TypeVar('T') @@ -7969,10 +8020,18 @@ class Foo(Generic[T]): def bar(self): pass baz = 3 + __magic__ = 4 + # The class attributes of the original class should be visible even # in dir() of the GenericAlias. See bpo-45755. - self.assertIn('bar', dir(Foo[int])) - self.assertIn('baz', dir(Foo[int])) + dir_items = set(dir(Foo[int])) + for required_item in [ + 'bar', 'baz', + '__args__', '__parameters__', '__origin__', + ]: + with self.subTest(required_item=required_item): + self.assertIn(required_item, dir_items) + self.assertNotIn('__magic__', dir_items) class RevealTypeTests(BaseTestCase): From webhook-mailer at python.org Mon Apr 10 10:57:48 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Mon, 10 Apr 2023 14:57:48 -0000 Subject: [Python-checkins] gh-97797: Mention `__metadata__` in docstrings of `typing.{_AnnotatedAlias, Annotated}` (#103405) Message-ID: https://github.com/python/cpython/commit/dc604a8c58af748ce25aee1af36b6521a3592fa5 commit: dc604a8c58af748ce25aee1af36b6521a3592fa5 branch: main author: Nikita Sobolev committer: AlexWaygood date: 2023-04-10T15:57:17+01:00 summary: gh-97797: Mention `__metadata__` in docstrings of `typing.{_AnnotatedAlias, Annotated}` (#103405) Co-authored-by: Alex Waygood Co-authored-by: Kirill <80244920+Eclips4 at users.noreply.github.com> files: M Lib/typing.py diff --git a/Lib/typing.py b/Lib/typing.py index 1f1c4ffa2566..7c165562c2b5 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2154,6 +2154,8 @@ class _AnnotatedAlias(_NotIterable, _GenericAlias, _root=True): with extra annotations. The alias behaves like a normal typing alias, instantiating is the same as instantiating the underlying type, binding it to types is also the same. + + The metadata itself is stored in a '__metadata__' attribute as a tuple. """ def __init__(self, origin, metadata): if isinstance(origin, _AnnotatedAlias): @@ -2209,6 +2211,10 @@ class Annotated: Details: - It's an error to call `Annotated` with less than two arguments. + - Access the metadata via the ``__metadata__`` attribute:: + + Annotated[int, '$'].__metadata__ == ('$',) + - Nested Annotated are flattened:: Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] From webhook-mailer at python.org Mon Apr 10 10:58:54 2023 From: webhook-mailer at python.org (miss-islington) Date: Mon, 10 Apr 2023 14:58:54 -0000 Subject: [Python-checkins] gh-103334: Ignore `Tools/c-analyzer/cpython/_parser.py` from `patchcheck` (GH-103335) Message-ID: https://github.com/python/cpython/commit/40db5c65b7ca4e784613b6122106a92576aba2d6 commit: 40db5c65b7ca4e784613b6122106a92576aba2d6 branch: main author: Nikita Sobolev committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-10T07:58:48-07:00 summary: gh-103334: Ignore `Tools/c-analyzer/cpython/_parser.py` from `patchcheck` (GH-103335) I've also added a small comment to `Tools/c-analyzer/cpython/_parser.py` to trigger the `patchcheck` CI. It must pass now. Automerge-Triggered-By: GH:ericsnowcurrently files: M Tools/c-analyzer/cpython/_parser.py M Tools/patchcheck/patchcheck.py diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index acf30e2c4020..d82fb967297c 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -47,6 +47,7 @@ def clean_lines(text): ''' # XXX Handle these. +# Tab separated: EXCLUDED = clean_lines(''' # @begin=conf@ diff --git a/Tools/patchcheck/patchcheck.py b/Tools/patchcheck/patchcheck.py index 44a6fb8c660c..fa3a43af6e60 100755 --- a/Tools/patchcheck/patchcheck.py +++ b/Tools/patchcheck/patchcheck.py @@ -170,12 +170,24 @@ def report_modified_files(file_paths): return "\n".join(lines) +#: Python files that have tabs by design: +_PYTHON_FILES_WITH_TABS = frozenset({ + 'Tools/c-analyzer/cpython/_parser.py', +}) + + @status("Fixing Python file whitespace", info=report_modified_files) def normalize_whitespace(file_paths): """Make sure that the whitespace for .py files have been normalized.""" reindent.makebackup = False # No need to create backups. - fixed = [path for path in file_paths if path.endswith('.py') and - reindent.check(os.path.join(SRCDIR, path))] + fixed = [ + path for path in file_paths + if ( + path.endswith('.py') + and path not in _PYTHON_FILES_WITH_TABS + and reindent.check(os.path.join(SRCDIR, path)) + ) + ] return fixed From webhook-mailer at python.org Mon Apr 10 11:21:53 2023 From: webhook-mailer at python.org (miss-islington) Date: Mon, 10 Apr 2023 15:21:53 -0000 Subject: [Python-checkins] gh-97797: Mention `__metadata__` in docstrings of `typing.{_AnnotatedAlias, Annotated}` (GH-103405) Message-ID: https://github.com/python/cpython/commit/0f6319fc8c01d202f1d20bd11c18d27974d9351d commit: 0f6319fc8c01d202f1d20bd11c18d27974d9351d branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-10T08:21:45-07:00 summary: gh-97797: Mention `__metadata__` in docstrings of `typing.{_AnnotatedAlias, Annotated}` (GH-103405) (cherry picked from commit dc604a8c58af748ce25aee1af36b6521a3592fa5) Co-authored-by: Nikita Sobolev Co-authored-by: Alex Waygood Co-authored-by: Kirill <80244920+Eclips4 at users.noreply.github.com> files: M Lib/typing.py diff --git a/Lib/typing.py b/Lib/typing.py index 8995564f8994..7a50e0603537 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2099,6 +2099,8 @@ class _AnnotatedAlias(_NotIterable, _GenericAlias, _root=True): with extra annotations. The alias behaves like a normal typing alias, instantiating is the same as instantiating the underlying type, binding it to types is also the same. + + The metadata itself is stored in a '__metadata__' attribute as a tuple. """ def __init__(self, origin, metadata): if isinstance(origin, _AnnotatedAlias): @@ -2151,6 +2153,10 @@ class Annotated: Details: - It's an error to call `Annotated` with less than two arguments. + - Access the metadata via the ``__metadata__`` attribute:: + + Annotated[int, '$'].__metadata__ == ('$',) + - Nested Annotated are flattened:: Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] From webhook-mailer at python.org Mon Apr 10 12:30:39 2023 From: webhook-mailer at python.org (carljm) Date: Mon, 10 Apr 2023 16:30:39 -0000 Subject: [Python-checkins] gh-103059: Clarify gc.freeze documentation (#103058) Message-ID: https://github.com/python/cpython/commit/8b1b17134e2241a8cdff9e0c869013a7ff3ca2fe commit: 8b1b17134e2241a8cdff9e0c869013a7ff3ca2fe branch: main author: raylu committer: carljm date: 2023-04-10T10:30:32-06:00 summary: gh-103059: Clarify gc.freeze documentation (#103058) files: M Doc/library/gc.rst M Misc/ACKS diff --git a/Doc/library/gc.rst b/Doc/library/gc.rst index 832ebaf497f3..6d5c64df1a1f 100644 --- a/Doc/library/gc.rst +++ b/Doc/library/gc.rst @@ -206,12 +206,17 @@ The :mod:`gc` module provides the following functions: .. function:: freeze() - Freeze all the objects tracked by gc - move them to a permanent generation - and ignore all the future collections. This can be used before a POSIX - fork() call to make the gc copy-on-write friendly or to speed up collection. - Also collection before a POSIX fork() call may free pages for future - allocation which can cause copy-on-write too so it's advised to disable gc - in parent process and freeze before fork and enable gc in child process. + Freeze all the objects tracked by the garbage collector; move them to a + permanent generation and ignore them in all the future collections. + + If a process will ``fork()`` without ``exec()``, avoiding unnecessary + copy-on-write in child processes will maximize memory sharing and reduce + overall memory usage. This requires both avoiding creation of freed "holes" + in memory pages in the parent process and ensuring that GC collections in + child processes won't touch the ``gc_refs`` counter of long-lived objects + originating in the parent process. To accomplish both, call ``gc.disable()`` + early in the parent process, ``gc.freeze()`` right before ``fork()``, and + ``gc.enable()`` early in child processes. .. versionadded:: 3.7 diff --git a/Misc/ACKS b/Misc/ACKS index 49f3692dfd6b..1e94d33a665e 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1115,6 +1115,7 @@ Jason Lowe Tony Lownds Ray Loyzaga Kang-Hao (Kenny) Lu +Raymond Lu Lukas Lueg Loren Luke Fredrik Lundh From webhook-mailer at python.org Mon Apr 10 13:09:41 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Mon, 10 Apr 2023 17:09:41 -0000 Subject: [Python-checkins] gh-83004: Harden `msvcrt` init (#103383) Message-ID: https://github.com/python/cpython/commit/c3cd3d10788769558a4668e9e5cfff42fe377852 commit: c3cd3d10788769558a4668e9e5cfff42fe377852 branch: main author: Erlend E. Aasland committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-04-10T22:39:33+05:30 summary: gh-83004: Harden `msvcrt` init (#103383) files: M PC/msvcrtmodule.c diff --git a/PC/msvcrtmodule.c b/PC/msvcrtmodule.c index face4d03af9d..6e8b423c3839 100644 --- a/PC/msvcrtmodule.c +++ b/PC/msvcrtmodule.c @@ -609,11 +609,11 @@ PyMODINIT_FUNC PyInit_msvcrt(void) { int st; - PyObject *d, *version; PyObject *m = PyModule_Create(&msvcrtmodule); - if (m == NULL) + if (m == NULL) { return NULL; - d = PyModule_GetDict(m); + } + PyObject *d = PyModule_GetDict(m); // Borrowed ref. /* constants for the locking() function's mode argument */ insertint(d, "LK_LOCK", _LK_LOCK); @@ -644,30 +644,47 @@ PyInit_msvcrt(void) #ifdef _VC_ASSEMBLY_PUBLICKEYTOKEN st = PyModule_AddStringConstant(m, "VC_ASSEMBLY_PUBLICKEYTOKEN", _VC_ASSEMBLY_PUBLICKEYTOKEN); - if (st < 0) return NULL; + if (st < 0) { + goto error; + } #endif #ifdef _CRT_ASSEMBLY_VERSION st = PyModule_AddStringConstant(m, "CRT_ASSEMBLY_VERSION", _CRT_ASSEMBLY_VERSION); - if (st < 0) return NULL; + if (st < 0) { + goto error; + } #endif #ifdef __LIBRARIES_ASSEMBLY_NAME_PREFIX st = PyModule_AddStringConstant(m, "LIBRARIES_ASSEMBLY_NAME_PREFIX", __LIBRARIES_ASSEMBLY_NAME_PREFIX); - if (st < 0) return NULL; + if (st < 0) { + goto error; + } #endif /* constants for the 2010 crt versions */ #if defined(_VC_CRT_MAJOR_VERSION) && defined (_VC_CRT_MINOR_VERSION) && defined(_VC_CRT_BUILD_VERSION) && defined(_VC_CRT_RBUILD_VERSION) - version = PyUnicode_FromFormat("%d.%d.%d.%d", _VC_CRT_MAJOR_VERSION, - _VC_CRT_MINOR_VERSION, - _VC_CRT_BUILD_VERSION, - _VC_CRT_RBUILD_VERSION); - st = PyModule_AddObject(m, "CRT_ASSEMBLY_VERSION", version); - if (st < 0) return NULL; + PyObject *version = PyUnicode_FromFormat("%d.%d.%d.%d", + _VC_CRT_MAJOR_VERSION, + _VC_CRT_MINOR_VERSION, + _VC_CRT_BUILD_VERSION, + _VC_CRT_RBUILD_VERSION); + if (version == NULL) { + goto error; + } + st = PyModule_AddObjectRef(m, "CRT_ASSEMBLY_VERSION", version); + Py_DECREF(version); + if (st < 0) { + goto error; + } #endif /* make compiler warning quiet if st is unused */ (void)st; return m; + +error: + Py_DECREF(m); + return NULL; } From webhook-mailer at python.org Mon Apr 10 13:17:55 2023 From: webhook-mailer at python.org (carljm) Date: Mon, 10 Apr 2023 17:17:55 -0000 Subject: [Python-checkins] [3.11] gh-103059: Clarify gc.freeze documentation (GH-103058) (#103416) Message-ID: https://github.com/python/cpython/commit/b80e4c89d8f385ca77a41e2d6302c95d7e10f391 commit: b80e4c89d8f385ca77a41e2d6302c95d7e10f391 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: carljm date: 2023-04-10T11:17:48-06:00 summary: [3.11] gh-103059: Clarify gc.freeze documentation (GH-103058) (#103416) gh-103059: Clarify gc.freeze documentation (GH-103058) (cherry picked from commit 8b1b17134e2241a8cdff9e0c869013a7ff3ca2fe) Co-authored-by: raylu files: M Doc/library/gc.rst M Misc/ACKS diff --git a/Doc/library/gc.rst b/Doc/library/gc.rst index 69a1a8313b75..42bb6dc3503f 100644 --- a/Doc/library/gc.rst +++ b/Doc/library/gc.rst @@ -206,12 +206,17 @@ The :mod:`gc` module provides the following functions: .. function:: freeze() - Freeze all the objects tracked by gc - move them to a permanent generation - and ignore all the future collections. This can be used before a POSIX - fork() call to make the gc copy-on-write friendly or to speed up collection. - Also collection before a POSIX fork() call may free pages for future - allocation which can cause copy-on-write too so it's advised to disable gc - in parent process and freeze before fork and enable gc in child process. + Freeze all the objects tracked by the garbage collector; move them to a + permanent generation and ignore them in all the future collections. + + If a process will ``fork()`` without ``exec()``, avoiding unnecessary + copy-on-write in child processes will maximize memory sharing and reduce + overall memory usage. This requires both avoiding creation of freed "holes" + in memory pages in the parent process and ensuring that GC collections in + child processes won't touch the ``gc_refs`` counter of long-lived objects + originating in the parent process. To accomplish both, call ``gc.disable()`` + early in the parent process, ``gc.freeze()`` right before ``fork()``, and + ``gc.enable()`` early in child processes. .. versionadded:: 3.7 diff --git a/Misc/ACKS b/Misc/ACKS index dbcff1e15435..c7c0677c5ba1 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1103,6 +1103,7 @@ Jason Lowe Tony Lownds Ray Loyzaga Kang-Hao (Kenny) Lu +Raymond Lu Lukas Lueg Loren Luke Fredrik Lundh From webhook-mailer at python.org Mon Apr 10 16:58:39 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Mon, 10 Apr 2023 20:58:39 -0000 Subject: [Python-checkins] gh-83004: Harden winreg init (#103386) Message-ID: https://github.com/python/cpython/commit/5ed2f19b3985a0a94c16d8a0285c13e1fbde9e69 commit: 5ed2f19b3985a0a94c16d8a0285c13e1fbde9e69 branch: main author: Erlend E. Aasland committer: erlend-aasland date: 2023-04-10T22:58:25+02:00 summary: gh-83004: Harden winreg init (#103386) files: M PC/winreg.c diff --git a/PC/winreg.c b/PC/winreg.c index 073598a12a68..15d32e7fcb99 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -2059,27 +2059,29 @@ static struct PyMethodDef winreg_methods[] = { NULL, }; -static void -insint(PyObject * d, char * name, long value) -{ - PyObject *v = PyLong_FromLong(value); - if (!v || PyDict_SetItemString(d, name, v)) - PyErr_Clear(); - Py_XDECREF(v); -} - -#define ADD_INT(val) insint(d, #val, val) +#define ADD_INT(VAL) do { \ + if (PyModule_AddIntConstant(m, #VAL, VAL) < 0) { \ + goto error; \ + } \ +} while (0) -static void -inskey(PyObject * d, char * name, HKEY key) +static int +inskey(PyObject *mod, char *name, HKEY key) { PyObject *v = PyLong_FromVoidPtr(key); - if (!v || PyDict_SetItemString(d, name, v)) - PyErr_Clear(); - Py_XDECREF(v); + if (v == NULL) { + return -1; + } + int rc = PyModule_AddObjectRef(mod, name, v); + Py_DECREF(v); + return rc; } -#define ADD_KEY(val) inskey(d, #val, val) +#define ADD_KEY(VAL) do { \ + if (inskey(m, #VAL, VAL) < 0) { \ + goto error; \ + } \ +} while (0) static struct PyModuleDef winregmodule = { @@ -2096,20 +2098,20 @@ static struct PyModuleDef winregmodule = { PyMODINIT_FUNC PyInit_winreg(void) { - PyObject *m, *d; - m = PyModule_Create(&winregmodule); - if (m == NULL) + PyObject *m = PyModule_Create(&winregmodule); + if (m == NULL) { return NULL; - d = PyModule_GetDict(m); + } PyHKEY_Type.tp_doc = PyHKEY_doc; - if (PyType_Ready(&PyHKEY_Type) < 0) - return NULL; - if (PyDict_SetItemString(d, "HKEYType", - (PyObject *)&PyHKEY_Type) != 0) - return NULL; - if (PyDict_SetItemString(d, "error", - PyExc_OSError) != 0) - return NULL; + if (PyType_Ready(&PyHKEY_Type) < 0) { + goto error; + } + if (PyModule_AddObjectRef(m, "HKEYType", (PyObject *)&PyHKEY_Type) < 0) { + goto error; + } + if (PyModule_AddObjectRef(m, "error", PyExc_OSError) < 0) { + goto error; + } /* Add the relevant constants */ ADD_KEY(HKEY_CLASSES_ROOT); @@ -2170,7 +2172,14 @@ PyMODINIT_FUNC PyInit_winreg(void) ADD_INT(REG_RESOURCE_LIST); ADD_INT(REG_FULL_RESOURCE_DESCRIPTOR); ADD_INT(REG_RESOURCE_REQUIREMENTS_LIST); + +#undef ADD_INT + return m; + +error: + Py_DECREF(m); + return NULL; } #endif /* MS_WINDOWS_DESKTOP || MS_WINDOWS_SYSTEM || MS_WINDOWS_GAMES */ From webhook-mailer at python.org Mon Apr 10 17:01:13 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Mon, 10 Apr 2023 21:01:13 -0000 Subject: [Python-checkins] gh-103092: Isolate winsound (#103249) Message-ID: https://github.com/python/cpython/commit/f80014a9b0e8d00df3e65379070be1dfd2721682 commit: f80014a9b0e8d00df3e65379070be1dfd2721682 branch: main author: AN Long committer: erlend-aasland date: 2023-04-10T23:01:05+02:00 summary: gh-103092: Isolate winsound (#103249) files: A Misc/NEWS.d/next/Library/2023-04-04-21-27-51.gh-issue-103092.7s7Bzf.rst M PC/winsound.c diff --git a/Misc/NEWS.d/next/Library/2023-04-04-21-27-51.gh-issue-103092.7s7Bzf.rst b/Misc/NEWS.d/next/Library/2023-04-04-21-27-51.gh-issue-103092.7s7Bzf.rst new file mode 100644 index 000000000000..39c62ffbe8c6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-04-21-27-51.gh-issue-103092.7s7Bzf.rst @@ -0,0 +1 @@ +Adapt the :mod:`winsound` extension module to :pep:`687`. diff --git a/PC/winsound.c b/PC/winsound.c index bae8e4497957..17ce2ef423b1 100644 --- a/PC/winsound.c +++ b/PC/winsound.c @@ -204,31 +204,13 @@ static struct PyMethodDef sound_methods[] = #define ADD_DEFINE(CONST) do { \ if (PyModule_AddIntConstant(module, #CONST, CONST) < 0) { \ - goto error; \ + return -1; \ } \ } while (0) - -static struct PyModuleDef winsoundmodule = { - PyModuleDef_HEAD_INIT, - "winsound", - sound_module_doc, - -1, - sound_methods, - NULL, - NULL, - NULL, - NULL -}; - -PyMODINIT_FUNC -PyInit_winsound(void) +static int +exec_module(PyObject *module) { - PyObject *module = PyModule_Create(&winsoundmodule); - if (module == NULL) { - return NULL; - } - ADD_DEFINE(SND_ASYNC); ADD_DEFINE(SND_NODEFAULT); ADD_DEFINE(SND_NOSTOP); @@ -248,9 +230,24 @@ PyInit_winsound(void) #undef ADD_DEFINE - return module; + return 0; +} + +static PyModuleDef_Slot sound_slots[] = { + {Py_mod_exec, exec_module}, + {0, NULL} +}; -error: - Py_DECREF(module); - return NULL; +static struct PyModuleDef winsoundmodule = { + .m_base = PyModuleDef_HEAD_INIT, + .m_name = "winsound", + .m_doc = sound_module_doc, + .m_methods = sound_methods, + .m_slots = sound_slots, +}; + +PyMODINIT_FUNC +PyInit_winsound(void) +{ + return PyModuleDef_Init(&winsoundmodule); } From webhook-mailer at python.org Mon Apr 10 17:51:07 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Mon, 10 Apr 2023 21:51:07 -0000 Subject: [Python-checkins] gh-103000: Optimise dataclasses asdict/astuple for common types (#103005) Message-ID: https://github.com/python/cpython/commit/d034590294d4618880375a6db513c30bce3e126b commit: d034590294d4618880375a6db513c30bce3e126b branch: main author: David Ellis committer: AlexWaygood date: 2023-04-10T22:50:58+01:00 summary: gh-103000: Optimise dataclasses asdict/astuple for common types (#103005) Co-authored-by: Carl Meyer Co-authored-by: Alex Waygood files: A Misc/NEWS.d/next/Library/2023-03-24-20-49-48.gh-issue-103000.6eVNZI.rst M Lib/dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 7558287bad44..4026c8b77975 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -222,6 +222,29 @@ def __repr__(self): # https://bugs.python.org/issue33453 for details. _MODULE_IDENTIFIER_RE = re.compile(r'^(?:\s*(\w+)\s*\.)?\s*(\w+)') +# Atomic immutable types which don't require any recursive handling and for which deepcopy +# returns the same object. We can provide a fast-path for these types in asdict and astuple. +_ATOMIC_TYPES = frozenset({ + # Common JSON Serializable types + types.NoneType, + bool, + int, + float, + str, + # Other common types + complex, + bytes, + # Other types that are also unaffected by deepcopy + types.EllipsisType, + types.NotImplementedType, + types.CodeType, + types.BuiltinFunctionType, + types.FunctionType, + type, + range, + property, +}) + # This function's logic is copied from "recursive_repr" function in # reprlib module to avoid dependency. def _recursive_repr(user_function): @@ -1291,7 +1314,9 @@ class C: def _asdict_inner(obj, dict_factory): - if _is_dataclass_instance(obj): + if type(obj) in _ATOMIC_TYPES: + return obj + elif _is_dataclass_instance(obj): result = [] for f in fields(obj): value = _asdict_inner(getattr(obj, f.name), dict_factory) @@ -1363,7 +1388,9 @@ class C: def _astuple_inner(obj, tuple_factory): - if _is_dataclass_instance(obj): + if type(obj) in _ATOMIC_TYPES: + return obj + elif _is_dataclass_instance(obj): result = [] for f in fields(obj): value = _astuple_inner(getattr(obj, f.name), tuple_factory) diff --git a/Misc/NEWS.d/next/Library/2023-03-24-20-49-48.gh-issue-103000.6eVNZI.rst b/Misc/NEWS.d/next/Library/2023-03-24-20-49-48.gh-issue-103000.6eVNZI.rst new file mode 100644 index 000000000000..15f16d9eb4c1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-24-20-49-48.gh-issue-103000.6eVNZI.rst @@ -0,0 +1,2 @@ +Improve performance of :func:`dataclasses.astuple` and +:func:`dataclasses.asdict` in cases where the contents are common Python types. From webhook-mailer at python.org Mon Apr 10 23:57:43 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Tue, 11 Apr 2023 03:57:43 -0000 Subject: [Python-checkins] Doc: Avoid error lexing multiprocessing docs code block on Pygments 2.15.0 (#103421) Message-ID: https://github.com/python/cpython/commit/75b6ab80da95f7d731b0d69b8ee8adb095b24d27 commit: 75b6ab80da95f7d731b0d69b8ee8adb095b24d27 branch: main author: C.A.M. Gerlach committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-04-10T20:57:36-07:00 summary: Doc: Avoid error lexing multiprocessing docs code block on Pygments 2.15.0 (#103421) files: M Doc/library/multiprocessing.rst diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 8454296b815b..84e309f1bc83 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -452,7 +452,9 @@ process which created it. importable by the children. This is covered in :ref:`multiprocessing-programming` however it is worth pointing out here. This means that some examples, such as the :class:`multiprocessing.pool.Pool` examples will not work in the - interactive interpreter. For example:: + interactive interpreter. For example: + + .. code-block:: text >>> from multiprocessing import Pool >>> p = Pool(5) From webhook-mailer at python.org Tue Apr 11 00:07:28 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 11 Apr 2023 04:07:28 -0000 Subject: [Python-checkins] Doc: Avoid error lexing multiprocessing docs code block on Pygments 2.15.0 (GH-103421) Message-ID: https://github.com/python/cpython/commit/4a05392adb1b0892c2d93bcf29170cd53e06b811 commit: 4a05392adb1b0892c2d93bcf29170cd53e06b811 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-10T21:07:21-07:00 summary: Doc: Avoid error lexing multiprocessing docs code block on Pygments 2.15.0 (GH-103421) (cherry picked from commit 75b6ab80da95f7d731b0d69b8ee8adb095b24d27) Co-authored-by: C.A.M. Gerlach files: M Doc/library/multiprocessing.rst diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index b5ceeb796f8f..6f0062012b38 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -445,7 +445,9 @@ process which created it. importable by the children. This is covered in :ref:`multiprocessing-programming` however it is worth pointing out here. This means that some examples, such as the :class:`multiprocessing.pool.Pool` examples will not work in the - interactive interpreter. For example:: + interactive interpreter. For example: + + .. code-block:: text >>> from multiprocessing import Pool >>> p = Pool(5) From webhook-mailer at python.org Tue Apr 11 02:17:42 2023 From: webhook-mailer at python.org (hugovk) Date: Tue, 11 Apr 2023 06:17:42 -0000 Subject: [Python-checkins] Docs: don't render files in includes/, they're for embedding only (#103313) Message-ID: https://github.com/python/cpython/commit/280bd536b58d3e844047cd132159cf9f6cb66708 commit: 280bd536b58d3e844047cd132159cf9f6cb66708 branch: main author: Hugo van Kemenade committer: hugovk date: 2023-04-11T09:17:34+03:00 summary: Docs: don't render files in includes/, they're for embedding only (#103313) files: M Doc/conf.py diff --git a/Doc/conf.py b/Doc/conf.py index 29fb63cbcc86..e99b801d0ae8 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -68,8 +68,10 @@ # Minimum version of sphinx required needs_sphinx = '3.2' +# Ignore any .rst files in the includes/ directory; +# they're embedded in pages but not rendered individually. # Ignore any .rst files in the venv/ directory. -exclude_patterns = ['venv/*', 'README.rst'] +exclude_patterns = ['includes/*.rst', 'venv/*', 'README.rst'] venvdir = os.getenv('VENVDIR') if venvdir is not None: exclude_patterns.append(venvdir + '/*') From webhook-mailer at python.org Tue Apr 11 02:26:14 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 11 Apr 2023 06:26:14 -0000 Subject: [Python-checkins] Docs: don't render files in includes/, they're for embedding only (GH-103313) Message-ID: https://github.com/python/cpython/commit/a836d7911193752d5fa27e3f101941ab339bd986 commit: a836d7911193752d5fa27e3f101941ab339bd986 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-10T23:26:07-07:00 summary: Docs: don't render files in includes/, they're for embedding only (GH-103313) (cherry picked from commit 280bd536b58d3e844047cd132159cf9f6cb66708) Co-authored-by: Hugo van Kemenade files: M Doc/conf.py diff --git a/Doc/conf.py b/Doc/conf.py index 982d6b40f66e..18aff5d58ce8 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -63,8 +63,10 @@ # Minimum version of sphinx required needs_sphinx = '3.2' +# Ignore any .rst files in the includes/ directory; +# they're embedded in pages but not rendered individually. # Ignore any .rst files in the venv/ directory. -exclude_patterns = ['venv/*', 'README.rst'] +exclude_patterns = ['includes/*.rst', 'venv/*', 'README.rst'] venvdir = os.getenv('VENVDIR') if venvdir is not None: exclude_patterns.append(venvdir + '/*') From webhook-mailer at python.org Tue Apr 11 02:45:01 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Tue, 11 Apr 2023 06:45:01 -0000 Subject: [Python-checkins] gh-99553: add tests for ExceptionGroup wrapping (#99615) Message-ID: https://github.com/python/cpython/commit/4cd1cc843aa4ae77a543cdd882da687300762e9d commit: 4cd1cc843aa4ae77a543cdd882da687300762e9d branch: main author: Zac Hatfield-Dodds committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-04-10T23:44:53-07:00 summary: gh-99553: add tests for ExceptionGroup wrapping (#99615) files: M Lib/test/test_exception_group.py diff --git a/Lib/test/test_exception_group.py b/Lib/test/test_exception_group.py index b11524e778e6..fa159a76ec1a 100644 --- a/Lib/test/test_exception_group.py +++ b/Lib/test/test_exception_group.py @@ -102,6 +102,20 @@ class MyEG(BaseExceptionGroup, ValueError): with self.assertRaisesRegex(TypeError, msg): MyEG("eg", [ValueError(12), KeyboardInterrupt(42)]) + def test_EG_and_specific_subclass_can_wrap_any_nonbase_exception(self): + class MyEG(ExceptionGroup, ValueError): + pass + + # The restriction is specific to Exception, not "the other base class" + MyEG("eg", [ValueError(12), Exception()]) + + def test_BEG_and_specific_subclass_can_wrap_any_nonbase_exception(self): + class MyEG(BaseExceptionGroup, ValueError): + pass + + # The restriction is specific to Exception, not "the other base class" + MyEG("eg", [ValueError(12), Exception()]) + def test_BEG_subclass_wraps_anything(self): class MyBEG(BaseExceptionGroup): From webhook-mailer at python.org Tue Apr 11 03:08:01 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 11 Apr 2023 07:08:01 -0000 Subject: [Python-checkins] gh-99553: add tests for ExceptionGroup wrapping (GH-99615) Message-ID: https://github.com/python/cpython/commit/254494c4b9e8454ebf8583da6bf108dba4c20d44 commit: 254494c4b9e8454ebf8583da6bf108dba4c20d44 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-11T00:07:25-07:00 summary: gh-99553: add tests for ExceptionGroup wrapping (GH-99615) (cherry picked from commit 4cd1cc843aa4ae77a543cdd882da687300762e9d) Co-authored-by: Zac Hatfield-Dodds files: M Lib/test/test_exception_group.py diff --git a/Lib/test/test_exception_group.py b/Lib/test/test_exception_group.py index 7fb45462e20f..a61af067cb2a 100644 --- a/Lib/test/test_exception_group.py +++ b/Lib/test/test_exception_group.py @@ -103,6 +103,20 @@ class MyEG(BaseExceptionGroup, ValueError): with self.assertRaisesRegex(TypeError, msg): MyEG("eg", [ValueError(12), KeyboardInterrupt(42)]) + def test_EG_and_specific_subclass_can_wrap_any_nonbase_exception(self): + class MyEG(ExceptionGroup, ValueError): + pass + + # The restriction is specific to Exception, not "the other base class" + MyEG("eg", [ValueError(12), Exception()]) + + def test_BEG_and_specific_subclass_can_wrap_any_nonbase_exception(self): + class MyEG(BaseExceptionGroup, ValueError): + pass + + # The restriction is specific to Exception, not "the other base class" + MyEG("eg", [ValueError(12), Exception()]) + def test_BEG_subclass_wraps_anything(self): class MyBEG(BaseExceptionGroup): From webhook-mailer at python.org Tue Apr 11 04:32:00 2023 From: webhook-mailer at python.org (iritkatriel) Date: Tue, 11 Apr 2023 08:32:00 -0000 Subject: [Python-checkins] gh-102828: set stacklevel on deprecation warning (#103422) Message-ID: https://github.com/python/cpython/commit/8026cda10ccd3cbc7f7ff84dc6970266512961e4 commit: 8026cda10ccd3cbc7f7ff84dc6970266512961e4 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-04-11T09:31:39+01:00 summary: gh-102828: set stacklevel on deprecation warning (#103422) files: M Lib/shutil.py diff --git a/Lib/shutil.py b/Lib/shutil.py index 8b378645a5a3..95b6c5299cab 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -699,7 +699,7 @@ def rmtree(path, ignore_errors=False, onerror=None, *, onexc=None, dir_fd=None): if onerror is not None: warnings.warn("onerror argument is deprecated, use onexc instead", - DeprecationWarning) + DeprecationWarning, stacklevel=2) sys.audit("shutil.rmtree", path, dir_fd) if ignore_errors: From webhook-mailer at python.org Tue Apr 11 04:38:45 2023 From: webhook-mailer at python.org (iritkatriel) Date: Tue, 11 Apr 2023 08:38:45 -0000 Subject: [Python-checkins] gh-103176: sys._current_exceptions() returns mapping to exception instances instead of exc_info tuples (#103177) Message-ID: https://github.com/python/cpython/commit/78b763f63032a7185c0905c319ead9e9b35787b6 commit: 78b763f63032a7185c0905c319ead9e9b35787b6 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-04-11T09:38:37+01:00 summary: gh-103176: sys._current_exceptions() returns mapping to exception instances instead of exc_info tuples (#103177) files: A Misc/NEWS.d/next/Library/2023-04-01-23-01-31.gh-issue-103176.FBsdxa.rst M Doc/library/sys.rst M Doc/whatsnew/3.12.rst M Lib/test/test_sys.py M Python/pystate.c diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 00721efd1cf6..e37d57edce51 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -220,6 +220,10 @@ always available. .. audit-event:: sys._current_exceptions "" sys._current_exceptions + .. versionchanged:: 3.12 + Each value in the dictionary is now a single exception instance, rather + than a 3-tuple as returned from ``sys.exc_info()``. + .. function:: breakpointhook() This hook function is called by built-in :func:`breakpoint`. By default, diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 651caed864fe..0eb16367267f 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -499,6 +499,10 @@ sys :data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback`. (Contributed by Irit Katriel in :gh:`102778`.) +* :func:`sys._current_exceptions` now returns a mapping from thread-id to an + exception instance, rather than to a ``(typ, exc, tb)`` tuple. + (Contributed by Irit Katriel in :gh:`103176`.) + Optimizations ============= @@ -940,6 +944,10 @@ Changes in the Python API synchronization is needed, implement locking within the cached property getter function or around multi-threaded access points. +* :func:`sys._current_exceptions` now returns a mapping from thread-id to an + exception instance, rather than to a ``(typ, exc, tb)`` tuple. + (Contributed by Irit Katriel in :gh:`103176`.) + Build Changes ============= diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index d7456d6d9480..890ffbf472c3 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -532,13 +532,13 @@ def g456(): main_id = threading.get_ident() self.assertIn(main_id, d) self.assertIn(thread_id, d) - self.assertEqual((None, None, None), d.pop(main_id)) + self.assertEqual(None, d.pop(main_id)) # Verify that the captured thread frame is blocked in g456, called # from f123. This is a little tricky, since various bits of # threading.py are also in the thread's call stack. - exc_type, exc_value, exc_tb = d.pop(thread_id) - stack = traceback.extract_stack(exc_tb.tb_frame) + exc_value = d.pop(thread_id) + stack = traceback.extract_stack(exc_value.__traceback__.tb_frame) for i, (filename, lineno, funcname, sourceline) in enumerate(stack): if funcname == "f123": break diff --git a/Misc/NEWS.d/next/Library/2023-04-01-23-01-31.gh-issue-103176.FBsdxa.rst b/Misc/NEWS.d/next/Library/2023-04-01-23-01-31.gh-issue-103176.FBsdxa.rst new file mode 100644 index 000000000000..b89f9bae5954 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-01-23-01-31.gh-issue-103176.FBsdxa.rst @@ -0,0 +1,2 @@ +:func:`sys._current_exceptions` now returns a mapping from thread-id to an +exception instance, rather than to a ``(typ, exc, tb)`` tuple. diff --git a/Python/pystate.c b/Python/pystate.c index d09c1d5743a4..37cef972e0fe 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1986,14 +1986,13 @@ _PyThread_CurrentExceptions(void) if (id == NULL) { goto fail; } - PyObject *exc_info = _PyErr_StackItemToExcInfoTuple(err_info); - if (exc_info == NULL) { - Py_DECREF(id); - goto fail; - } - int stat = PyDict_SetItem(result, id, exc_info); + PyObject *exc = err_info->exc_value; + assert(exc == NULL || + exc == Py_None || + PyExceptionInstance_Check(exc)); + + int stat = PyDict_SetItem(result, id, exc == NULL ? Py_None : exc); Py_DECREF(id); - Py_DECREF(exc_info); if (stat < 0) { goto fail; } From webhook-mailer at python.org Tue Apr 11 06:15:53 2023 From: webhook-mailer at python.org (iritkatriel) Date: Tue, 11 Apr 2023 10:15:53 -0000 Subject: [Python-checkins] gh-87092: move assembler related code from compile.c to assemble.c (#103277) Message-ID: https://github.com/python/cpython/commit/33822d037a3381d239dcc532937138da6f3da669 commit: 33822d037a3381d239dcc532937138da6f3da669 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-04-11T11:15:09+01:00 summary: gh-87092: move assembler related code from compile.c to assemble.c (#103277) files: A Python/assemble.c M Include/internal/pycore_compile.h M Include/internal/pycore_flowgraph.h M Makefile.pre.in M PCbuild/_freeze_module.vcxproj M PCbuild/_freeze_module.vcxproj.filters M PCbuild/pythoncore.vcxproj M PCbuild/pythoncore.vcxproj.filters M Python/compile.c M Python/flowgraph.c diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h index 6a1e02c0b895..f85240c48a89 100644 --- a/Include/internal/pycore_compile.h +++ b/Include/internal/pycore_compile.h @@ -33,6 +33,45 @@ extern int _PyAST_Optimize( struct _arena *arena, _PyASTOptimizeState *state); + +typedef struct { + int i_opcode; + int i_oparg; + _PyCompilerSrcLocation i_loc; +} _PyCompilerInstruction; + +typedef struct { + _PyCompilerInstruction *s_instrs; + int s_allocated; + int s_used; + + int *s_labelmap; /* label id --> instr offset */ + int s_labelmap_size; + int s_next_free_label; /* next free label id */ +} _PyCompile_InstructionSequence; + +typedef struct { + PyObject *u_name; + PyObject *u_qualname; /* dot-separated qualified name (lazy) */ + + /* The following fields are dicts that map objects to + the index of them in co_XXX. The index is used as + the argument for opcodes that refer to those collections. + */ + PyObject *u_consts; /* all constants */ + PyObject *u_names; /* all names */ + PyObject *u_varnames; /* local variables */ + PyObject *u_cellvars; /* cell variables */ + PyObject *u_freevars; /* free variables */ + + Py_ssize_t u_argcount; /* number of arguments for block */ + Py_ssize_t u_posonlyargcount; /* number of positional only arguments for block */ + Py_ssize_t u_kwonlyargcount; /* number of keyword only arguments for block */ + + int u_firstlineno; /* the first lineno of the block */ +} _PyCompile_CodeUnitMetadata; + + /* Utility for a number of growing arrays used in the compiler */ int _PyCompile_EnsureArrayLargeEnough( int idx, diff --git a/Include/internal/pycore_flowgraph.h b/Include/internal/pycore_flowgraph.h index 7c0b8fe980c3..f470dad3aaa4 100644 --- a/Include/internal/pycore_flowgraph.h +++ b/Include/internal/pycore_flowgraph.h @@ -9,6 +9,7 @@ extern "C" { #endif #include "pycore_opcode_utils.h" +#include "pycore_compile.h" static const _PyCompilerSrcLocation NO_LOCATION = {-1, -1, -1, -1}; @@ -33,7 +34,8 @@ typedef struct { typedef struct _PyCfgBasicblock_ { /* Each basicblock in a compilation unit is linked via b_list in the reverse order that the block are allocated. b_list points to the next - block, not to be confused with b_next, which is next by control flow. */ + block in this list, not to be confused with b_next, which is next by + control flow. */ struct _PyCfgBasicblock_ *b_list; /* The label of this block if it is a jump target, -1 otherwise */ _PyCfgJumpTargetLabel b_label; @@ -91,10 +93,9 @@ void _PyCfgBuilder_Fini(_PyCfgBuilder *g); _PyCfgInstruction* _PyCfg_BasicblockLastInstr(const _PyCfgBasicblock *b); int _PyCfg_OptimizeCodeUnit(_PyCfgBuilder *g, PyObject *consts, PyObject *const_cache, - int code_flags, int nlocals, int nparams); + int code_flags, int nlocals, int nparams, int firstlineno); int _PyCfg_Stackdepth(_PyCfgBasicblock *entryblock, int code_flags); void _PyCfg_ConvertExceptionHandlersToNops(_PyCfgBasicblock *entryblock); -int _PyCfg_ResolveLineNumbers(_PyCfgBuilder *g, int firstlineno); int _PyCfg_ResolveJumps(_PyCfgBuilder *g); int _PyCfg_InstrSize(_PyCfgInstruction *instruction); @@ -110,6 +111,10 @@ basicblock_nofallthrough(const _PyCfgBasicblock *b) { #define BB_NO_FALLTHROUGH(B) (basicblock_nofallthrough(B)) #define BB_HAS_FALLTHROUGH(B) (!basicblock_nofallthrough(B)) +PyCodeObject * +_PyAssemble_MakeCodeObject(_PyCompile_CodeUnitMetadata *u, PyObject *const_cache, + PyObject *consts, int maxdepth, _PyCfgBasicblock *entryblock, + int nlocalsplus, int code_flags, PyObject *filename); #ifdef __cplusplus } diff --git a/Makefile.pre.in b/Makefile.pre.in index fefa5d4e8147..dc22683361d4 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -369,17 +369,18 @@ PYTHON_OBJS= \ Python/Python-ast.o \ Python/Python-tokenize.o \ Python/asdl.o \ + Python/assemble.o \ Python/ast.o \ Python/ast_opt.o \ Python/ast_unparse.o \ Python/bltinmodule.o \ Python/ceval.o \ - Python/flowgraph.o \ Python/codecs.o \ Python/compile.o \ Python/context.o \ Python/dynamic_annotations.o \ Python/errors.o \ + Python/flowgraph.o \ Python/frame.o \ Python/frozenmain.o \ Python/future.o \ diff --git a/PCbuild/_freeze_module.vcxproj b/PCbuild/_freeze_module.vcxproj index 28eced6d4b28..70ca0787cfd6 100644 --- a/PCbuild/_freeze_module.vcxproj +++ b/PCbuild/_freeze_module.vcxproj @@ -177,13 +177,13 @@ + - @@ -192,6 +192,7 @@ + diff --git a/PCbuild/_freeze_module.vcxproj.filters b/PCbuild/_freeze_module.vcxproj.filters index e4faa89bb831..464cbec62a62 100644 --- a/PCbuild/_freeze_module.vcxproj.filters +++ b/PCbuild/_freeze_module.vcxproj.filters @@ -28,6 +28,9 @@ Source Files + + Source Files + Source Files @@ -76,9 +79,6 @@ Source Files - - Source Files - Source Files @@ -142,6 +142,9 @@ Source Files + + Source Files + Source Files diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 29f32db579fa..a465f99eca82 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -500,13 +500,13 @@ + - @@ -514,6 +514,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 6a622fd93930..52cd4bbb6fb1 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -1094,6 +1094,9 @@ Python + + Python + Python @@ -1109,9 +1112,6 @@ Python - - Python - Python @@ -1130,6 +1130,9 @@ Python + + Python + Python diff --git a/Python/assemble.c b/Python/assemble.c new file mode 100644 index 000000000000..e5a361b230cf --- /dev/null +++ b/Python/assemble.c @@ -0,0 +1,602 @@ +#include + +#include "Python.h" +#include "pycore_flowgraph.h" +#include "pycore_compile.h" +#include "pycore_pymem.h" // _PyMem_IsPtrFreed() +#include "pycore_code.h" // write_location_entry_start() + + +#define DEFAULT_CODE_SIZE 128 +#define DEFAULT_LNOTAB_SIZE 16 +#define DEFAULT_CNOTAB_SIZE 32 + +#undef SUCCESS +#undef ERROR +#define SUCCESS 0 +#define ERROR -1 + +#define RETURN_IF_ERROR(X) \ + if ((X) == -1) { \ + return ERROR; \ + } + +typedef _PyCompilerSrcLocation location; +typedef _PyCfgInstruction cfg_instr; +typedef _PyCfgBasicblock basicblock; + +static inline bool +same_location(location a, location b) +{ + return a.lineno == b.lineno && + a.end_lineno == b.end_lineno && + a.col_offset == b.col_offset && + a.end_col_offset == b.end_col_offset; +} + +struct assembler { + PyObject *a_bytecode; /* bytes containing bytecode */ + int a_offset; /* offset into bytecode */ + PyObject *a_except_table; /* bytes containing exception table */ + int a_except_table_off; /* offset into exception table */ + /* Location Info */ + int a_lineno; /* lineno of last emitted instruction */ + PyObject* a_linetable; /* bytes containing location info */ + int a_location_off; /* offset of last written location info frame */ +}; + +static int +assemble_init(struct assembler *a, int firstlineno) +{ + memset(a, 0, sizeof(struct assembler)); + a->a_lineno = firstlineno; + a->a_linetable = NULL; + a->a_location_off = 0; + a->a_except_table = NULL; + a->a_bytecode = PyBytes_FromStringAndSize(NULL, DEFAULT_CODE_SIZE); + if (a->a_bytecode == NULL) { + goto error; + } + a->a_linetable = PyBytes_FromStringAndSize(NULL, DEFAULT_CNOTAB_SIZE); + if (a->a_linetable == NULL) { + goto error; + } + a->a_except_table = PyBytes_FromStringAndSize(NULL, DEFAULT_LNOTAB_SIZE); + if (a->a_except_table == NULL) { + goto error; + } + return SUCCESS; +error: + Py_XDECREF(a->a_bytecode); + Py_XDECREF(a->a_linetable); + Py_XDECREF(a->a_except_table); + return ERROR; +} + +static void +assemble_free(struct assembler *a) +{ + Py_XDECREF(a->a_bytecode); + Py_XDECREF(a->a_linetable); + Py_XDECREF(a->a_except_table); +} + +static inline void +write_except_byte(struct assembler *a, int byte) { + unsigned char *p = (unsigned char *) PyBytes_AS_STRING(a->a_except_table); + p[a->a_except_table_off++] = byte; +} + +#define CONTINUATION_BIT 64 + +static void +assemble_emit_exception_table_item(struct assembler *a, int value, int msb) +{ + assert ((msb | 128) == 128); + assert(value >= 0 && value < (1 << 30)); + if (value >= 1 << 24) { + write_except_byte(a, (value >> 24) | CONTINUATION_BIT | msb); + msb = 0; + } + if (value >= 1 << 18) { + write_except_byte(a, ((value >> 18)&0x3f) | CONTINUATION_BIT | msb); + msb = 0; + } + if (value >= 1 << 12) { + write_except_byte(a, ((value >> 12)&0x3f) | CONTINUATION_BIT | msb); + msb = 0; + } + if (value >= 1 << 6) { + write_except_byte(a, ((value >> 6)&0x3f) | CONTINUATION_BIT | msb); + msb = 0; + } + write_except_byte(a, (value&0x3f) | msb); +} + +/* See Objects/exception_handling_notes.txt for details of layout */ +#define MAX_SIZE_OF_ENTRY 20 + +static int +assemble_emit_exception_table_entry(struct assembler *a, int start, int end, basicblock *handler) +{ + Py_ssize_t len = PyBytes_GET_SIZE(a->a_except_table); + if (a->a_except_table_off + MAX_SIZE_OF_ENTRY >= len) { + RETURN_IF_ERROR(_PyBytes_Resize(&a->a_except_table, len * 2)); + } + int size = end-start; + assert(end > start); + int target = handler->b_offset; + int depth = handler->b_startdepth - 1; + if (handler->b_preserve_lasti) { + depth -= 1; + } + assert(depth >= 0); + int depth_lasti = (depth<<1) | handler->b_preserve_lasti; + assemble_emit_exception_table_item(a, start, (1<<7)); + assemble_emit_exception_table_item(a, size, 0); + assemble_emit_exception_table_item(a, target, 0); + assemble_emit_exception_table_item(a, depth_lasti, 0); + return SUCCESS; +} + +static int +assemble_exception_table(struct assembler *a, basicblock *entryblock) +{ + basicblock *b; + int ioffset = 0; + basicblock *handler = NULL; + int start = -1; + for (b = entryblock; b != NULL; b = b->b_next) { + ioffset = b->b_offset; + for (int i = 0; i < b->b_iused; i++) { + cfg_instr *instr = &b->b_instr[i]; + if (instr->i_except != handler) { + if (handler != NULL) { + RETURN_IF_ERROR( + assemble_emit_exception_table_entry(a, start, ioffset, handler)); + } + start = ioffset; + handler = instr->i_except; + } + ioffset += _PyCfg_InstrSize(instr); + } + } + if (handler != NULL) { + RETURN_IF_ERROR(assemble_emit_exception_table_entry(a, start, ioffset, handler)); + } + return SUCCESS; +} + + +/* Code location emitting code. See locations.md for a description of the format. */ + +#define MSB 0x80 + +static void +write_location_byte(struct assembler* a, int val) +{ + PyBytes_AS_STRING(a->a_linetable)[a->a_location_off] = val&255; + a->a_location_off++; +} + + +static uint8_t * +location_pointer(struct assembler* a) +{ + return (uint8_t *)PyBytes_AS_STRING(a->a_linetable) + + a->a_location_off; +} + +static void +write_location_first_byte(struct assembler* a, int code, int length) +{ + a->a_location_off += write_location_entry_start( + location_pointer(a), code, length); +} + +static void +write_location_varint(struct assembler* a, unsigned int val) +{ + uint8_t *ptr = location_pointer(a); + a->a_location_off += write_varint(ptr, val); +} + + +static void +write_location_signed_varint(struct assembler* a, int val) +{ + uint8_t *ptr = location_pointer(a); + a->a_location_off += write_signed_varint(ptr, val); +} + +static void +write_location_info_short_form(struct assembler* a, int length, int column, int end_column) +{ + assert(length > 0 && length <= 8); + int column_low_bits = column & 7; + int column_group = column >> 3; + assert(column < 80); + assert(end_column >= column); + assert(end_column - column < 16); + write_location_first_byte(a, PY_CODE_LOCATION_INFO_SHORT0 + column_group, length); + write_location_byte(a, (column_low_bits << 4) | (end_column - column)); +} + +static void +write_location_info_oneline_form(struct assembler* a, int length, int line_delta, int column, int end_column) +{ + assert(length > 0 && length <= 8); + assert(line_delta >= 0 && line_delta < 3); + assert(column < 128); + assert(end_column < 128); + write_location_first_byte(a, PY_CODE_LOCATION_INFO_ONE_LINE0 + line_delta, length); + write_location_byte(a, column); + write_location_byte(a, end_column); +} + +static void +write_location_info_long_form(struct assembler* a, location loc, int length) +{ + assert(length > 0 && length <= 8); + write_location_first_byte(a, PY_CODE_LOCATION_INFO_LONG, length); + write_location_signed_varint(a, loc.lineno - a->a_lineno); + assert(loc.end_lineno >= loc.lineno); + write_location_varint(a, loc.end_lineno - loc.lineno); + write_location_varint(a, loc.col_offset + 1); + write_location_varint(a, loc.end_col_offset + 1); +} + +static void +write_location_info_none(struct assembler* a, int length) +{ + write_location_first_byte(a, PY_CODE_LOCATION_INFO_NONE, length); +} + +static void +write_location_info_no_column(struct assembler* a, int length, int line_delta) +{ + write_location_first_byte(a, PY_CODE_LOCATION_INFO_NO_COLUMNS, length); + write_location_signed_varint(a, line_delta); +} + +#define THEORETICAL_MAX_ENTRY_SIZE 25 /* 1 + 6 + 6 + 6 + 6 */ + + +static int +write_location_info_entry(struct assembler* a, location loc, int isize) +{ + Py_ssize_t len = PyBytes_GET_SIZE(a->a_linetable); + if (a->a_location_off + THEORETICAL_MAX_ENTRY_SIZE >= len) { + assert(len > THEORETICAL_MAX_ENTRY_SIZE); + RETURN_IF_ERROR(_PyBytes_Resize(&a->a_linetable, len*2)); + } + if (loc.lineno < 0) { + write_location_info_none(a, isize); + return SUCCESS; + } + int line_delta = loc.lineno - a->a_lineno; + int column = loc.col_offset; + int end_column = loc.end_col_offset; + assert(column >= -1); + assert(end_column >= -1); + if (column < 0 || end_column < 0) { + if (loc.end_lineno == loc.lineno || loc.end_lineno == -1) { + write_location_info_no_column(a, isize, line_delta); + a->a_lineno = loc.lineno; + return SUCCESS; + } + } + else if (loc.end_lineno == loc.lineno) { + if (line_delta == 0 && column < 80 && end_column - column < 16 && end_column >= column) { + write_location_info_short_form(a, isize, column, end_column); + return SUCCESS; + } + if (line_delta >= 0 && line_delta < 3 && column < 128 && end_column < 128) { + write_location_info_oneline_form(a, isize, line_delta, column, end_column); + a->a_lineno = loc.lineno; + return SUCCESS; + } + } + write_location_info_long_form(a, loc, isize); + a->a_lineno = loc.lineno; + return SUCCESS; +} + +static int +assemble_emit_location(struct assembler* a, location loc, int isize) +{ + if (isize == 0) { + return SUCCESS; + } + while (isize > 8) { + RETURN_IF_ERROR(write_location_info_entry(a, loc, 8)); + isize -= 8; + } + return write_location_info_entry(a, loc, isize); +} + +static int +assemble_location_info(struct assembler *a, basicblock *entryblock, int firstlineno) +{ + a->a_lineno = firstlineno; + location loc = NO_LOCATION; + int size = 0; + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + for (int j = 0; j < b->b_iused; j++) { + if (!same_location(loc, b->b_instr[j].i_loc)) { + RETURN_IF_ERROR(assemble_emit_location(a, loc, size)); + loc = b->b_instr[j].i_loc; + size = 0; + } + size += _PyCfg_InstrSize(&b->b_instr[j]); + } + } + RETURN_IF_ERROR(assemble_emit_location(a, loc, size)); + return SUCCESS; +} + +static void +write_instr(_Py_CODEUNIT *codestr, cfg_instr *instruction, int ilen) +{ + int opcode = instruction->i_opcode; + assert(!IS_PSEUDO_OPCODE(opcode)); + int oparg = instruction->i_oparg; + assert(HAS_ARG(opcode) || oparg == 0); + int caches = _PyOpcode_Caches[opcode]; + switch (ilen - caches) { + case 4: + codestr->op.code = EXTENDED_ARG; + codestr->op.arg = (oparg >> 24) & 0xFF; + codestr++; + /* fall through */ + case 3: + codestr->op.code = EXTENDED_ARG; + codestr->op.arg = (oparg >> 16) & 0xFF; + codestr++; + /* fall through */ + case 2: + codestr->op.code = EXTENDED_ARG; + codestr->op.arg = (oparg >> 8) & 0xFF; + codestr++; + /* fall through */ + case 1: + codestr->op.code = opcode; + codestr->op.arg = oparg & 0xFF; + codestr++; + break; + default: + Py_UNREACHABLE(); + } + while (caches--) { + codestr->op.code = CACHE; + codestr->op.arg = 0; + codestr++; + } +} + +/* assemble_emit_instr() + Extend the bytecode with a new instruction. + Update lnotab if necessary. +*/ + +static int +assemble_emit_instr(struct assembler *a, cfg_instr *i) +{ + Py_ssize_t len = PyBytes_GET_SIZE(a->a_bytecode); + _Py_CODEUNIT *code; + + int size = _PyCfg_InstrSize(i); + if (a->a_offset + size >= len / (int)sizeof(_Py_CODEUNIT)) { + if (len > PY_SSIZE_T_MAX / 2) { + return ERROR; + } + RETURN_IF_ERROR(_PyBytes_Resize(&a->a_bytecode, len * 2)); + } + code = (_Py_CODEUNIT *)PyBytes_AS_STRING(a->a_bytecode) + a->a_offset; + a->a_offset += size; + write_instr(code, i, size); + return SUCCESS; +} + +static int +assemble_emit(struct assembler *a, basicblock *entryblock, int first_lineno, + PyObject *const_cache) +{ + RETURN_IF_ERROR(assemble_init(a, first_lineno)); + + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + for (int j = 0; j < b->b_iused; j++) { + RETURN_IF_ERROR(assemble_emit_instr(a, &b->b_instr[j])); + } + } + + RETURN_IF_ERROR(assemble_location_info(a, entryblock, a->a_lineno)); + + RETURN_IF_ERROR(assemble_exception_table(a, entryblock)); + + RETURN_IF_ERROR(_PyBytes_Resize(&a->a_except_table, a->a_except_table_off)); + RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_except_table)); + + RETURN_IF_ERROR(_PyBytes_Resize(&a->a_linetable, a->a_location_off)); + RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_linetable)); + + RETURN_IF_ERROR(_PyBytes_Resize(&a->a_bytecode, a->a_offset * sizeof(_Py_CODEUNIT))); + RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_bytecode)); + return SUCCESS; +} + +static PyObject * +dict_keys_inorder(PyObject *dict, Py_ssize_t offset) +{ + PyObject *tuple, *k, *v; + Py_ssize_t i, pos = 0, size = PyDict_GET_SIZE(dict); + + tuple = PyTuple_New(size); + if (tuple == NULL) + return NULL; + while (PyDict_Next(dict, &pos, &k, &v)) { + i = PyLong_AS_LONG(v); + assert((i - offset) < size); + assert((i - offset) >= 0); + PyTuple_SET_ITEM(tuple, i - offset, Py_NewRef(k)); + } + return tuple; +} + +// This is in codeobject.c. +extern void _Py_set_localsplus_info(int, PyObject *, unsigned char, + PyObject *, PyObject *); + +static void +compute_localsplus_info(_PyCompile_CodeUnitMetadata *umd, int nlocalsplus, + PyObject *names, PyObject *kinds) +{ + PyObject *k, *v; + Py_ssize_t pos = 0; + while (PyDict_Next(umd->u_varnames, &pos, &k, &v)) { + int offset = (int)PyLong_AS_LONG(v); + assert(offset >= 0); + assert(offset < nlocalsplus); + // For now we do not distinguish arg kinds. + _PyLocals_Kind kind = CO_FAST_LOCAL; + if (PyDict_GetItem(umd->u_cellvars, k) != NULL) { + kind |= CO_FAST_CELL; + } + _Py_set_localsplus_info(offset, k, kind, names, kinds); + } + int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); + + // This counter mirrors the fix done in fix_cell_offsets(). + int numdropped = 0; + pos = 0; + while (PyDict_Next(umd->u_cellvars, &pos, &k, &v)) { + if (PyDict_GetItem(umd->u_varnames, k) != NULL) { + // Skip cells that are already covered by locals. + numdropped += 1; + continue; + } + int offset = (int)PyLong_AS_LONG(v); + assert(offset >= 0); + offset += nlocals - numdropped; + assert(offset < nlocalsplus); + _Py_set_localsplus_info(offset, k, CO_FAST_CELL, names, kinds); + } + + pos = 0; + while (PyDict_Next(umd->u_freevars, &pos, &k, &v)) { + int offset = (int)PyLong_AS_LONG(v); + assert(offset >= 0); + offset += nlocals - numdropped; + assert(offset < nlocalsplus); + _Py_set_localsplus_info(offset, k, CO_FAST_FREE, names, kinds); + } +} + +static PyCodeObject * +makecode(_PyCompile_CodeUnitMetadata *umd, struct assembler *a, PyObject *const_cache, + PyObject *constslist, int maxdepth, int nlocalsplus, int code_flags, + PyObject *filename) +{ + PyCodeObject *co = NULL; + PyObject *names = NULL; + PyObject *consts = NULL; + PyObject *localsplusnames = NULL; + PyObject *localspluskinds = NULL; + names = dict_keys_inorder(umd->u_names, 0); + if (!names) { + goto error; + } + if (_PyCompile_ConstCacheMergeOne(const_cache, &names) < 0) { + goto error; + } + + consts = PyList_AsTuple(constslist); /* PyCode_New requires a tuple */ + if (consts == NULL) { + goto error; + } + if (_PyCompile_ConstCacheMergeOne(const_cache, &consts) < 0) { + goto error; + } + + assert(umd->u_posonlyargcount < INT_MAX); + assert(umd->u_argcount < INT_MAX); + assert(umd->u_kwonlyargcount < INT_MAX); + int posonlyargcount = (int)umd->u_posonlyargcount; + int posorkwargcount = (int)umd->u_argcount; + assert(INT_MAX - posonlyargcount - posorkwargcount > 0); + int kwonlyargcount = (int)umd->u_kwonlyargcount; + + localsplusnames = PyTuple_New(nlocalsplus); + if (localsplusnames == NULL) { + goto error; + } + localspluskinds = PyBytes_FromStringAndSize(NULL, nlocalsplus); + if (localspluskinds == NULL) { + goto error; + } + compute_localsplus_info(umd, nlocalsplus, localsplusnames, localspluskinds); + + struct _PyCodeConstructor con = { + .filename = filename, + .name = umd->u_name, + .qualname = umd->u_qualname ? umd->u_qualname : umd->u_name, + .flags = code_flags, + + .code = a->a_bytecode, + .firstlineno = umd->u_firstlineno, + .linetable = a->a_linetable, + + .consts = consts, + .names = names, + + .localsplusnames = localsplusnames, + .localspluskinds = localspluskinds, + + .argcount = posonlyargcount + posorkwargcount, + .posonlyargcount = posonlyargcount, + .kwonlyargcount = kwonlyargcount, + + .stacksize = maxdepth, + + .exceptiontable = a->a_except_table, + }; + + if (_PyCode_Validate(&con) < 0) { + goto error; + } + + if (_PyCompile_ConstCacheMergeOne(const_cache, &localsplusnames) < 0) { + goto error; + } + con.localsplusnames = localsplusnames; + + co = _PyCode_New(&con); + if (co == NULL) { + goto error; + } + +error: + Py_XDECREF(names); + Py_XDECREF(consts); + Py_XDECREF(localsplusnames); + Py_XDECREF(localspluskinds); + return co; +} + + +PyCodeObject * +_PyAssemble_MakeCodeObject(_PyCompile_CodeUnitMetadata *umd, PyObject *const_cache, + PyObject *consts, int maxdepth, basicblock *entryblock, + int nlocalsplus, int code_flags, PyObject *filename) +{ + PyCodeObject *co = NULL; + + struct assembler a; + int res = assemble_emit(&a, entryblock, umd->u_firstlineno, const_cache); + if (res == SUCCESS) { + co = makecode(umd, &a, const_cache, consts, maxdepth, nlocalsplus, + code_flags, filename); + } + assemble_free(&a); + return co; +} diff --git a/Python/compile.c b/Python/compile.c index fed9ae7066e4..15fca8296c69 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -6,10 +6,10 @@ * object: * 1. Checks for future statements. See future.c * 2. Builds a symbol table. See symtable.c. - * 3. Generate code for basic blocks. See compiler_mod() in this file. - * 4. Assemble the basic blocks into final code. See assemble() in - * this file. - * 5. Optimize the byte code (peephole optimizations). + * 3. Generate an instruction sequence. See compiler_mod() in this file. + * 4. Generate a control flow graph and run optimizations on it. See flowgraph.c. + * 5. Assemble the basic blocks into final code. See optimize_and_assemble() in + * this file, and assembler.c. * * Note that compiler_mod() suggests module, but the module ast type * (mod_ty) has cases for expressions and interactive statements. @@ -101,15 +101,6 @@ location_is_after(location loc1, location loc2) { (loc1.col_offset > loc2.end_col_offset)); } -static inline bool -same_location(location a, location b) -{ - return a.lineno == b.lineno && - a.end_lineno == b.end_lineno && - a.col_offset == b.col_offset && - a.end_col_offset == b.end_col_offset; -} - #define LOC(x) SRC_LOCATION_FROM_AST(x) typedef _PyCfgJumpTargetLabel jump_target_label; @@ -129,46 +120,6 @@ static jump_target_label NO_LABEL = {-1}; RETURN_IF_ERROR(instr_sequence_use_label(INSTR_SEQUENCE(C), (LBL).id)) -static void -write_instr(_Py_CODEUNIT *codestr, cfg_instr *instruction, int ilen) -{ - int opcode = instruction->i_opcode; - assert(!IS_PSEUDO_OPCODE(opcode)); - int oparg = instruction->i_oparg; - assert(HAS_ARG(opcode) || oparg == 0); - int caches = _PyOpcode_Caches[opcode]; - switch (ilen - caches) { - case 4: - codestr->op.code = EXTENDED_ARG; - codestr->op.arg = (oparg >> 24) & 0xFF; - codestr++; - /* fall through */ - case 3: - codestr->op.code = EXTENDED_ARG; - codestr->op.arg = (oparg >> 16) & 0xFF; - codestr++; - /* fall through */ - case 2: - codestr->op.code = EXTENDED_ARG; - codestr->op.arg = (oparg >> 8) & 0xFF; - codestr++; - /* fall through */ - case 1: - codestr->op.code = opcode; - codestr->op.arg = oparg & 0xFF; - codestr++; - break; - default: - Py_UNREACHABLE(); - } - while (caches--) { - codestr->op.code = CACHE; - codestr->op.arg = 0; - codestr++; - } -} - - /* fblockinfo tracks the current frame block. A frame block is used to handle loops, try/except, and try/finally. @@ -198,21 +149,8 @@ enum { COMPILER_SCOPE_COMPREHENSION, }; -typedef struct { - int i_opcode; - int i_oparg; - location i_loc; -} instruction; - -typedef struct instr_sequence_ { - instruction *s_instrs; - int s_allocated; - int s_used; - - int *s_labelmap; /* label id --> instr offset */ - int s_labelmap_size; - int s_next_free_label; /* next free label id */ -} instr_sequence; +typedef _PyCompilerInstruction instruction; +typedef _PyCompile_InstructionSequence instr_sequence; #define INITIAL_INSTR_SEQUENCE_SIZE 100 #define INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE 10 @@ -314,7 +252,6 @@ static int instr_sequence_addop(instr_sequence *seq, int opcode, int oparg, location loc) { assert(IS_WITHIN_OPCODE_RANGE(opcode)); - assert(!IS_ASSEMBLER_OPCODE(opcode)); assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0); assert(0 <= oparg && oparg < (1 << 30)); @@ -432,32 +369,17 @@ instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { struct compiler_unit { PySTEntryObject *u_ste; - PyObject *u_name; - PyObject *u_qualname; /* dot-separated qualified name (lazy) */ int u_scope_type; - /* The following fields are dicts that map objects to - the index of them in co_XXX. The index is used as - the argument for opcodes that refer to those collections. - */ - PyObject *u_consts; /* all constants */ - PyObject *u_names; /* all names */ - PyObject *u_varnames; /* local variables */ - PyObject *u_cellvars; /* cell variables */ - PyObject *u_freevars; /* free variables */ PyObject *u_private; /* for private name mangling */ - Py_ssize_t u_argcount; /* number of arguments for block */ - Py_ssize_t u_posonlyargcount; /* number of positional only arguments for block */ - Py_ssize_t u_kwonlyargcount; /* number of keyword only arguments for block */ - instr_sequence u_instr_sequence; /* codegen output */ int u_nfblocks; struct fblockinfo u_fblock[CO_MAXBLOCKS]; - int u_firstlineno; /* the first lineno of the block */ + _PyCompile_CodeUnitMetadata u_metadata; }; /* This struct captures the global state of a compilation. @@ -566,7 +488,7 @@ static int compiler_match(struct compiler *, stmt_ty); static int compiler_pattern_subpattern(struct compiler *, pattern_ty, pattern_context *); -static PyCodeObject *assemble(struct compiler *, int addNone); +static PyCodeObject *optimize_and_assemble(struct compiler *, int addNone); #define CAPSULE_NAME "compile.c compiler unit" @@ -750,13 +672,13 @@ compiler_unit_free(struct compiler_unit *u) { instr_sequence_fini(&u->u_instr_sequence); Py_CLEAR(u->u_ste); - Py_CLEAR(u->u_name); - Py_CLEAR(u->u_qualname); - Py_CLEAR(u->u_consts); - Py_CLEAR(u->u_names); - Py_CLEAR(u->u_varnames); - Py_CLEAR(u->u_freevars); - Py_CLEAR(u->u_cellvars); + Py_CLEAR(u->u_metadata.u_name); + Py_CLEAR(u->u_metadata.u_qualname); + Py_CLEAR(u->u_metadata.u_consts); + Py_CLEAR(u->u_metadata.u_names); + Py_CLEAR(u->u_metadata.u_varnames); + Py_CLEAR(u->u_metadata.u_freevars); + Py_CLEAR(u->u_metadata.u_cellvars); Py_CLEAR(u->u_private); PyObject_Free(u); } @@ -783,8 +705,8 @@ compiler_set_qualname(struct compiler *c) if (u->u_scope_type == COMPILER_SCOPE_FUNCTION || u->u_scope_type == COMPILER_SCOPE_ASYNC_FUNCTION || u->u_scope_type == COMPILER_SCOPE_CLASS) { - assert(u->u_name); - mangled = _Py_Mangle(parent->u_private, u->u_name); + assert(u->u_metadata.u_name); + mangled = _Py_Mangle(parent->u_private, u->u_metadata.u_name); if (!mangled) { return ERROR; } @@ -802,14 +724,14 @@ compiler_set_qualname(struct compiler *c) || parent->u_scope_type == COMPILER_SCOPE_LAMBDA) { _Py_DECLARE_STR(dot_locals, "."); - base = PyUnicode_Concat(parent->u_qualname, + base = PyUnicode_Concat(parent->u_metadata.u_qualname, &_Py_STR(dot_locals)); if (base == NULL) { return ERROR; } } else { - base = Py_NewRef(parent->u_qualname); + base = Py_NewRef(parent->u_metadata.u_qualname); } } } @@ -821,15 +743,15 @@ compiler_set_qualname(struct compiler *c) if (name == NULL) { return ERROR; } - PyUnicode_Append(&name, u->u_name); + PyUnicode_Append(&name, u->u_metadata.u_name); if (name == NULL) { return ERROR; } } else { - name = Py_NewRef(u->u_name); + name = Py_NewRef(u->u_metadata.u_name); } - u->u_qualname = name; + u->u_metadata.u_qualname = name; return SUCCESS; } @@ -930,6 +852,7 @@ static int codegen_addop_noarg(instr_sequence *seq, int opcode, location loc) { assert(!HAS_ARG(opcode)); + assert(!IS_ASSEMBLER_OPCODE(opcode)); return instr_sequence_addop(seq, opcode, 0, loc); } @@ -1077,7 +1000,7 @@ compiler_add_const(PyObject *const_cache, struct compiler_unit *u, PyObject *o) return ERROR; } - Py_ssize_t arg = dict_add_o(u->u_consts, key); + Py_ssize_t arg = dict_add_o(u->u_metadata.u_consts, key); Py_DECREF(key); return arg; } @@ -1140,6 +1063,7 @@ codegen_addop_i(instr_sequence *seq, int opcode, Py_ssize_t oparg, location loc) EXTENDED_ARG is used for 16, 24, and 32-bit arguments. */ int oparg_ = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int); + assert(!IS_ASSEMBLER_OPCODE(opcode)); return instr_sequence_addop(seq, opcode, oparg_, loc); } @@ -1149,6 +1073,7 @@ codegen_addop_j(instr_sequence *seq, location loc, { assert(IS_LABEL(target)); assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); + assert(!IS_ASSEMBLER_OPCODE(opcode)); return instr_sequence_addop(seq, opcode, target.id, loc); } @@ -1180,7 +1105,7 @@ codegen_addop_j(instr_sequence *seq, location loc, #define ADDOP_N(C, LOC, OP, O, TYPE) { \ assert(!HAS_CONST(OP)); /* use ADDOP_LOAD_CONST_NEW */ \ - if (compiler_addop_o((C)->u, (LOC), (OP), (C)->u->u_ ## TYPE, (O)) < 0) { \ + if (compiler_addop_o((C)->u, (LOC), (OP), (C)->u->u_metadata.u_ ## TYPE, (O)) < 0) { \ Py_DECREF((O)); \ return ERROR; \ } \ @@ -1188,7 +1113,7 @@ codegen_addop_j(instr_sequence *seq, location loc, } #define ADDOP_NAME(C, LOC, OP, O, TYPE) \ - RETURN_IF_ERROR(compiler_addop_name((C)->u, (LOC), (OP), (C)->u->u_ ## TYPE, (O))) + RETURN_IF_ERROR(compiler_addop_name((C)->u, (LOC), (OP), (C)->u->u_metadata.u_ ## TYPE, (O))) #define ADDOP_I(C, LOC, OP, O) \ RETURN_IF_ERROR(codegen_addop_i(INSTR_SEQUENCE(C), (OP), (O), (LOC))) @@ -1265,18 +1190,18 @@ compiler_enter_scope(struct compiler *c, identifier name, return ERROR; } u->u_scope_type = scope_type; - u->u_argcount = 0; - u->u_posonlyargcount = 0; - u->u_kwonlyargcount = 0; + u->u_metadata.u_argcount = 0; + u->u_metadata.u_posonlyargcount = 0; + u->u_metadata.u_kwonlyargcount = 0; u->u_ste = PySymtable_Lookup(c->c_st, key); if (!u->u_ste) { compiler_unit_free(u); return ERROR; } - u->u_name = Py_NewRef(name); - u->u_varnames = list2dict(u->u_ste->ste_varnames); - u->u_cellvars = dictbytype(u->u_ste->ste_symbols, CELL, 0, 0); - if (!u->u_varnames || !u->u_cellvars) { + u->u_metadata.u_name = Py_NewRef(name); + u->u_metadata.u_varnames = list2dict(u->u_ste->ste_varnames); + u->u_metadata.u_cellvars = dictbytype(u->u_ste->ste_symbols, CELL, 0, 0); + if (!u->u_metadata.u_varnames || !u->u_metadata.u_cellvars) { compiler_unit_free(u); return ERROR; } @@ -1284,8 +1209,8 @@ compiler_enter_scope(struct compiler *c, identifier name, /* Cook up an implicit __class__ cell. */ int res; assert(u->u_scope_type == COMPILER_SCOPE_CLASS); - assert(PyDict_GET_SIZE(u->u_cellvars) == 0); - res = PyDict_SetItem(u->u_cellvars, &_Py_ID(__class__), + assert(PyDict_GET_SIZE(u->u_metadata.u_cellvars) == 0); + res = PyDict_SetItem(u->u_metadata.u_cellvars, &_Py_ID(__class__), _PyLong_GetZero()); if (res < 0) { compiler_unit_free(u); @@ -1293,22 +1218,22 @@ compiler_enter_scope(struct compiler *c, identifier name, } } - u->u_freevars = dictbytype(u->u_ste->ste_symbols, FREE, DEF_FREE_CLASS, - PyDict_GET_SIZE(u->u_cellvars)); - if (!u->u_freevars) { + u->u_metadata.u_freevars = dictbytype(u->u_ste->ste_symbols, FREE, DEF_FREE_CLASS, + PyDict_GET_SIZE(u->u_metadata.u_cellvars)); + if (!u->u_metadata.u_freevars) { compiler_unit_free(u); return ERROR; } u->u_nfblocks = 0; - u->u_firstlineno = lineno; - u->u_consts = PyDict_New(); - if (!u->u_consts) { + u->u_metadata.u_firstlineno = lineno; + u->u_metadata.u_consts = PyDict_New(); + if (!u->u_metadata.u_consts) { compiler_unit_free(u); return ERROR; } - u->u_names = PyDict_New(); - if (!u->u_names) { + u->u_metadata.u_names = PyDict_New(); + if (!u->u_metadata.u_names) { compiler_unit_free(u); return ERROR; } @@ -1667,7 +1592,7 @@ compiler_body(struct compiler *c, location loc, asdl_stmt_seq *stmts) /* Set current line number to the line number of first statement. This way line number for SETUP_ANNOTATIONS will always coincide with the line number of first "real" statement in module. - If body is empty, then lineno will be set later in assemble. */ + If body is empty, then lineno will be set later in optimize_and_assemble. */ if (c->u->u_scope_type == COMPILER_SCOPE_MODULE && asdl_seq_LEN(stmts)) { st = (stmt_ty)asdl_seq_GET(stmts, 0); loc = LOC(st); @@ -1738,7 +1663,7 @@ compiler_mod(struct compiler *c, mod_ty mod) if (compiler_codegen(c, mod) < 0) { return NULL; } - PyCodeObject *co = assemble(c, addNone); + PyCodeObject *co = optimize_and_assemble(c, addNone); compiler_exit_scope(c); return co; } @@ -1762,8 +1687,8 @@ get_ref_type(struct compiler *c, PyObject *name) "unknown scope in unit %S (%R); " "symbols: %R; locals: %R; globals: %R", name, - c->u->u_name, c->u->u_ste->ste_id, - c->u->u_ste->ste_symbols, c->u->u_varnames, c->u->u_names); + c->u->u_metadata.u_name, c->u->u_ste->ste_id, + c->u->u_ste->ste_symbols, c->u->u_metadata.u_varnames, c->u->u_metadata.u_names); return ERROR; } return scope; @@ -1803,10 +1728,10 @@ compiler_make_closure(struct compiler *c, location loc, } int arg; if (reftype == CELL) { - arg = compiler_lookup_arg(c->u->u_cellvars, name); + arg = compiler_lookup_arg(c->u->u_metadata.u_cellvars, name); } else { - arg = compiler_lookup_arg(c->u->u_freevars, name); + arg = compiler_lookup_arg(c->u->u_metadata.u_freevars, name); } if (arg == -1) { PyObject *freevars = _PyCode_GetFreevars(co); @@ -1818,7 +1743,7 @@ compiler_make_closure(struct compiler *c, location loc, "freevars of code %S: %R", name, reftype, - c->u->u_name, + c->u->u_metadata.u_name, co->co_name, freevars); Py_DECREF(freevars); @@ -2187,9 +2112,9 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) return ERROR; } - c->u->u_argcount = asdl_seq_LEN(args->args); - c->u->u_posonlyargcount = asdl_seq_LEN(args->posonlyargs); - c->u->u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs); + c->u->u_metadata.u_argcount = asdl_seq_LEN(args->args); + c->u->u_metadata.u_posonlyargcount = asdl_seq_LEN(args->posonlyargs); + c->u->u_metadata.u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs); for (i = docstring ? 1 : 0; i < asdl_seq_LEN(body); i++) { VISIT_IN_SCOPE(c, stmt, (stmt_ty)asdl_seq_GET(body, i)); } @@ -2199,7 +2124,7 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) return ERROR; } } - co = assemble(c, 1); + co = optimize_and_assemble(c, 1); compiler_exit_scope(c); if (co == NULL) { Py_XDECREF(co); @@ -2259,8 +2184,8 @@ compiler_class(struct compiler *c, stmt_ty s) compiler_exit_scope(c); return ERROR; } - assert(c->u->u_qualname); - ADDOP_LOAD_CONST(c, loc, c->u->u_qualname); + assert(c->u->u_metadata.u_qualname); + ADDOP_LOAD_CONST(c, loc, c->u->u_metadata.u_qualname); if (compiler_nameop(c, loc, &_Py_ID(__qualname__), Store) < 0) { compiler_exit_scope(c); return ERROR; @@ -2274,7 +2199,7 @@ compiler_class(struct compiler *c, stmt_ty s) /* Return __classcell__ if it is referenced, otherwise return None */ if (c->u->u_ste->ste_needs_class_closure) { /* Store __classcell__ into class namespace & return it */ - i = compiler_lookup_arg(c->u->u_cellvars, &_Py_ID(__class__)); + i = compiler_lookup_arg(c->u->u_metadata.u_cellvars, &_Py_ID(__class__)); if (i < 0) { compiler_exit_scope(c); return ERROR; @@ -2289,12 +2214,12 @@ compiler_class(struct compiler *c, stmt_ty s) } else { /* No methods referenced __class__, so just return None */ - assert(PyDict_GET_SIZE(c->u->u_cellvars) == 0); + assert(PyDict_GET_SIZE(c->u->u_metadata.u_cellvars) == 0); ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); } ADDOP_IN_SCOPE(c, NO_LOCATION, RETURN_VALUE); /* create the code object */ - co = assemble(c, 1); + co = optimize_and_assemble(c, 1); } /* leave the new scope */ compiler_exit_scope(c); @@ -2561,17 +2486,17 @@ compiler_lambda(struct compiler *c, expr_ty e) docstring. */ RETURN_IF_ERROR(compiler_add_const(c->c_const_cache, c->u, Py_None)); - c->u->u_argcount = asdl_seq_LEN(args->args); - c->u->u_posonlyargcount = asdl_seq_LEN(args->posonlyargs); - c->u->u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs); + c->u->u_metadata.u_argcount = asdl_seq_LEN(args->args); + c->u->u_metadata.u_posonlyargcount = asdl_seq_LEN(args->posonlyargs); + c->u->u_metadata.u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs); VISIT_IN_SCOPE(c, expr, e->v.Lambda.body); if (c->u->u_ste->ste_generator) { - co = assemble(c, 0); + co = optimize_and_assemble(c, 0); } else { location loc = LOCATION(e->lineno, e->lineno, 0, 0); ADDOP_IN_SCOPE(c, loc, RETURN_VALUE); - co = assemble(c, 1); + co = optimize_and_assemble(c, 1); } compiler_exit_scope(c); if (co == NULL) { @@ -3717,7 +3642,7 @@ compiler_nameop(struct compiler *c, location loc, Py_ssize_t arg; enum { OP_FAST, OP_GLOBAL, OP_DEREF, OP_NAME } optype; - PyObject *dict = c->u->u_names; + PyObject *dict = c->u->u_metadata.u_names; PyObject *mangled; assert(!_PyUnicode_EqualToASCIIString(name, "None") && @@ -3738,11 +3663,11 @@ compiler_nameop(struct compiler *c, location loc, scope = _PyST_GetScope(c->u->u_ste, mangled); switch (scope) { case FREE: - dict = c->u->u_freevars; + dict = c->u->u_metadata.u_freevars; optype = OP_DEREF; break; case CELL: - dict = c->u->u_cellvars; + dict = c->u->u_metadata.u_cellvars; optype = OP_DEREF; break; case LOCAL: @@ -4708,7 +4633,7 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc, if (gen_index == 0) { /* Receive outermost iter as an implicit argument */ - c->u->u_argcount = 1; + c->u->u_metadata.u_argcount = 1; ADDOP_I(c, loc, LOAD_FAST, 0); } else { @@ -4821,7 +4746,7 @@ compiler_async_comprehension_generator(struct compiler *c, location loc, if (gen_index == 0) { /* Receive outermost iter as an implicit argument */ - c->u->u_argcount = 1; + c->u->u_metadata.u_argcount = 1; ADDOP_I(c, loc, LOAD_FAST, 0); } else { @@ -4969,7 +4894,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, } } - co = assemble(c, 1); + co = optimize_and_assemble(c, 1); compiler_exit_scope(c); if (is_top_level_await && is_async_generator){ c->u->u_ste->ste_coroutine = 1; @@ -6592,378 +6517,6 @@ compiler_match(struct compiler *c, stmt_ty s) #undef WILDCARD_CHECK #undef WILDCARD_STAR_CHECK - -/* End of the compiler section, beginning of the assembler section */ - - -struct assembler { - PyObject *a_bytecode; /* bytes containing bytecode */ - int a_offset; /* offset into bytecode */ - PyObject *a_except_table; /* bytes containing exception table */ - int a_except_table_off; /* offset into exception table */ - /* Location Info */ - int a_lineno; /* lineno of last emitted instruction */ - PyObject* a_linetable; /* bytes containing location info */ - int a_location_off; /* offset of last written location info frame */ -}; - -static int -assemble_init(struct assembler *a, int firstlineno) -{ - memset(a, 0, sizeof(struct assembler)); - a->a_lineno = firstlineno; - a->a_linetable = NULL; - a->a_location_off = 0; - a->a_except_table = NULL; - a->a_bytecode = PyBytes_FromStringAndSize(NULL, DEFAULT_CODE_SIZE); - if (a->a_bytecode == NULL) { - goto error; - } - a->a_linetable = PyBytes_FromStringAndSize(NULL, DEFAULT_CNOTAB_SIZE); - if (a->a_linetable == NULL) { - goto error; - } - a->a_except_table = PyBytes_FromStringAndSize(NULL, DEFAULT_LNOTAB_SIZE); - if (a->a_except_table == NULL) { - goto error; - } - return SUCCESS; -error: - Py_XDECREF(a->a_bytecode); - Py_XDECREF(a->a_linetable); - Py_XDECREF(a->a_except_table); - return ERROR; -} - -static void -assemble_free(struct assembler *a) -{ - Py_XDECREF(a->a_bytecode); - Py_XDECREF(a->a_linetable); - Py_XDECREF(a->a_except_table); -} - -static inline void -write_except_byte(struct assembler *a, int byte) { - unsigned char *p = (unsigned char *) PyBytes_AS_STRING(a->a_except_table); - p[a->a_except_table_off++] = byte; -} - -#define CONTINUATION_BIT 64 - -static void -assemble_emit_exception_table_item(struct assembler *a, int value, int msb) -{ - assert ((msb | 128) == 128); - assert(value >= 0 && value < (1 << 30)); - if (value >= 1 << 24) { - write_except_byte(a, (value >> 24) | CONTINUATION_BIT | msb); - msb = 0; - } - if (value >= 1 << 18) { - write_except_byte(a, ((value >> 18)&0x3f) | CONTINUATION_BIT | msb); - msb = 0; - } - if (value >= 1 << 12) { - write_except_byte(a, ((value >> 12)&0x3f) | CONTINUATION_BIT | msb); - msb = 0; - } - if (value >= 1 << 6) { - write_except_byte(a, ((value >> 6)&0x3f) | CONTINUATION_BIT | msb); - msb = 0; - } - write_except_byte(a, (value&0x3f) | msb); -} - -/* See Objects/exception_handling_notes.txt for details of layout */ -#define MAX_SIZE_OF_ENTRY 20 - -static int -assemble_emit_exception_table_entry(struct assembler *a, int start, int end, basicblock *handler) -{ - Py_ssize_t len = PyBytes_GET_SIZE(a->a_except_table); - if (a->a_except_table_off + MAX_SIZE_OF_ENTRY >= len) { - RETURN_IF_ERROR(_PyBytes_Resize(&a->a_except_table, len * 2)); - } - int size = end-start; - assert(end > start); - int target = handler->b_offset; - int depth = handler->b_startdepth - 1; - if (handler->b_preserve_lasti) { - depth -= 1; - } - assert(depth >= 0); - int depth_lasti = (depth<<1) | handler->b_preserve_lasti; - assemble_emit_exception_table_item(a, start, (1<<7)); - assemble_emit_exception_table_item(a, size, 0); - assemble_emit_exception_table_item(a, target, 0); - assemble_emit_exception_table_item(a, depth_lasti, 0); - return SUCCESS; -} - -static int -assemble_exception_table(struct assembler *a, basicblock *entryblock) -{ - basicblock *b; - int ioffset = 0; - basicblock *handler = NULL; - int start = -1; - for (b = entryblock; b != NULL; b = b->b_next) { - ioffset = b->b_offset; - for (int i = 0; i < b->b_iused; i++) { - cfg_instr *instr = &b->b_instr[i]; - if (instr->i_except != handler) { - if (handler != NULL) { - RETURN_IF_ERROR( - assemble_emit_exception_table_entry(a, start, ioffset, handler)); - } - start = ioffset; - handler = instr->i_except; - } - ioffset += _PyCfg_InstrSize(instr); - } - } - if (handler != NULL) { - RETURN_IF_ERROR(assemble_emit_exception_table_entry(a, start, ioffset, handler)); - } - return SUCCESS; -} - -/* Code location emitting code. See locations.md for a description of the format. */ - -#define MSB 0x80 - -static void -write_location_byte(struct assembler* a, int val) -{ - PyBytes_AS_STRING(a->a_linetable)[a->a_location_off] = val&255; - a->a_location_off++; -} - - -static uint8_t * -location_pointer(struct assembler* a) -{ - return (uint8_t *)PyBytes_AS_STRING(a->a_linetable) + - a->a_location_off; -} - -static void -write_location_first_byte(struct assembler* a, int code, int length) -{ - a->a_location_off += write_location_entry_start( - location_pointer(a), code, length); -} - -static void -write_location_varint(struct assembler* a, unsigned int val) -{ - uint8_t *ptr = location_pointer(a); - a->a_location_off += write_varint(ptr, val); -} - - -static void -write_location_signed_varint(struct assembler* a, int val) -{ - uint8_t *ptr = location_pointer(a); - a->a_location_off += write_signed_varint(ptr, val); -} - -static void -write_location_info_short_form(struct assembler* a, int length, int column, int end_column) -{ - assert(length > 0 && length <= 8); - int column_low_bits = column & 7; - int column_group = column >> 3; - assert(column < 80); - assert(end_column >= column); - assert(end_column - column < 16); - write_location_first_byte(a, PY_CODE_LOCATION_INFO_SHORT0 + column_group, length); - write_location_byte(a, (column_low_bits << 4) | (end_column - column)); -} - -static void -write_location_info_oneline_form(struct assembler* a, int length, int line_delta, int column, int end_column) -{ - assert(length > 0 && length <= 8); - assert(line_delta >= 0 && line_delta < 3); - assert(column < 128); - assert(end_column < 128); - write_location_first_byte(a, PY_CODE_LOCATION_INFO_ONE_LINE0 + line_delta, length); - write_location_byte(a, column); - write_location_byte(a, end_column); -} - -static void -write_location_info_long_form(struct assembler* a, location loc, int length) -{ - assert(length > 0 && length <= 8); - write_location_first_byte(a, PY_CODE_LOCATION_INFO_LONG, length); - write_location_signed_varint(a, loc.lineno - a->a_lineno); - assert(loc.end_lineno >= loc.lineno); - write_location_varint(a, loc.end_lineno - loc.lineno); - write_location_varint(a, loc.col_offset + 1); - write_location_varint(a, loc.end_col_offset + 1); -} - -static void -write_location_info_none(struct assembler* a, int length) -{ - write_location_first_byte(a, PY_CODE_LOCATION_INFO_NONE, length); -} - -static void -write_location_info_no_column(struct assembler* a, int length, int line_delta) -{ - write_location_first_byte(a, PY_CODE_LOCATION_INFO_NO_COLUMNS, length); - write_location_signed_varint(a, line_delta); -} - -#define THEORETICAL_MAX_ENTRY_SIZE 25 /* 1 + 6 + 6 + 6 + 6 */ - -static int -write_location_info_entry(struct assembler* a, location loc, int isize) -{ - Py_ssize_t len = PyBytes_GET_SIZE(a->a_linetable); - if (a->a_location_off + THEORETICAL_MAX_ENTRY_SIZE >= len) { - assert(len > THEORETICAL_MAX_ENTRY_SIZE); - RETURN_IF_ERROR(_PyBytes_Resize(&a->a_linetable, len*2)); - } - if (loc.lineno < 0) { - write_location_info_none(a, isize); - return SUCCESS; - } - int line_delta = loc.lineno - a->a_lineno; - int column = loc.col_offset; - int end_column = loc.end_col_offset; - assert(column >= -1); - assert(end_column >= -1); - if (column < 0 || end_column < 0) { - if (loc.end_lineno == loc.lineno || loc.end_lineno == -1) { - write_location_info_no_column(a, isize, line_delta); - a->a_lineno = loc.lineno; - return SUCCESS; - } - } - else if (loc.end_lineno == loc.lineno) { - if (line_delta == 0 && column < 80 && end_column - column < 16 && end_column >= column) { - write_location_info_short_form(a, isize, column, end_column); - return SUCCESS; - } - if (line_delta >= 0 && line_delta < 3 && column < 128 && end_column < 128) { - write_location_info_oneline_form(a, isize, line_delta, column, end_column); - a->a_lineno = loc.lineno; - return SUCCESS; - } - } - write_location_info_long_form(a, loc, isize); - a->a_lineno = loc.lineno; - return SUCCESS; -} - -static int -assemble_emit_location(struct assembler* a, location loc, int isize) -{ - if (isize == 0) { - return SUCCESS; - } - while (isize > 8) { - RETURN_IF_ERROR(write_location_info_entry(a, loc, 8)); - isize -= 8; - } - return write_location_info_entry(a, loc, isize); -} - -static int -assemble_location_info(struct assembler *a, basicblock *entryblock, int firstlineno) -{ - a->a_lineno = firstlineno; - location loc = NO_LOCATION; - int size = 0; - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - for (int j = 0; j < b->b_iused; j++) { - if (!same_location(loc, b->b_instr[j].i_loc)) { - RETURN_IF_ERROR(assemble_emit_location(a, loc, size)); - loc = b->b_instr[j].i_loc; - size = 0; - } - size += _PyCfg_InstrSize(&b->b_instr[j]); - } - } - RETURN_IF_ERROR(assemble_emit_location(a, loc, size)); - return SUCCESS; -} - -/* assemble_emit_instr() - Extend the bytecode with a new instruction. - Update lnotab if necessary. -*/ - -static int -assemble_emit_instr(struct assembler *a, cfg_instr *i) -{ - Py_ssize_t len = PyBytes_GET_SIZE(a->a_bytecode); - _Py_CODEUNIT *code; - - int size = _PyCfg_InstrSize(i); - if (a->a_offset + size >= len / (int)sizeof(_Py_CODEUNIT)) { - if (len > PY_SSIZE_T_MAX / 2) { - return ERROR; - } - RETURN_IF_ERROR(_PyBytes_Resize(&a->a_bytecode, len * 2)); - } - code = (_Py_CODEUNIT *)PyBytes_AS_STRING(a->a_bytecode) + a->a_offset; - a->a_offset += size; - write_instr(code, i, size); - return SUCCESS; -} - -static int -assemble_emit(struct assembler *a, basicblock *entryblock, int first_lineno, - PyObject *const_cache) -{ - RETURN_IF_ERROR(assemble_init(a, first_lineno)); - - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - for (int j = 0; j < b->b_iused; j++) { - RETURN_IF_ERROR(assemble_emit_instr(a, &b->b_instr[j])); - } - } - - RETURN_IF_ERROR(assemble_location_info(a, entryblock, a->a_lineno)); - - RETURN_IF_ERROR(assemble_exception_table(a, entryblock)); - - RETURN_IF_ERROR(_PyBytes_Resize(&a->a_except_table, a->a_except_table_off)); - RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_except_table)); - - RETURN_IF_ERROR(_PyBytes_Resize(&a->a_linetable, a->a_location_off)); - RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_linetable)); - - RETURN_IF_ERROR(_PyBytes_Resize(&a->a_bytecode, a->a_offset * sizeof(_Py_CODEUNIT))); - RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_bytecode)); - return SUCCESS; -} - -static PyObject * -dict_keys_inorder(PyObject *dict, Py_ssize_t offset) -{ - PyObject *tuple, *k, *v; - Py_ssize_t i, pos = 0, size = PyDict_GET_SIZE(dict); - - tuple = PyTuple_New(size); - if (tuple == NULL) - return NULL; - while (PyDict_Next(dict, &pos, &k, &v)) { - i = PyLong_AS_LONG(v); - assert((i - offset) < size); - assert((i - offset) >= 0); - PyTuple_SET_ITEM(tuple, i - offset, Py_NewRef(k)); - } - return tuple; -} - static PyObject * consts_dict_keys_inorder(PyObject *dict) { @@ -7051,153 +6604,13 @@ _PyCompile_ConstCacheMergeOne(PyObject *const_cache, PyObject **obj) return SUCCESS; } -// This is in codeobject.c. -extern void _Py_set_localsplus_info(int, PyObject *, unsigned char, - PyObject *, PyObject *); - -static void -compute_localsplus_info(struct compiler_unit *u, int nlocalsplus, - PyObject *names, PyObject *kinds) -{ - PyObject *k, *v; - Py_ssize_t pos = 0; - while (PyDict_Next(u->u_varnames, &pos, &k, &v)) { - int offset = (int)PyLong_AS_LONG(v); - assert(offset >= 0); - assert(offset < nlocalsplus); - // For now we do not distinguish arg kinds. - _PyLocals_Kind kind = CO_FAST_LOCAL; - if (PyDict_GetItem(u->u_cellvars, k) != NULL) { - kind |= CO_FAST_CELL; - } - _Py_set_localsplus_info(offset, k, kind, names, kinds); - } - int nlocals = (int)PyDict_GET_SIZE(u->u_varnames); - - // This counter mirrors the fix done in fix_cell_offsets(). - int numdropped = 0; - pos = 0; - while (PyDict_Next(u->u_cellvars, &pos, &k, &v)) { - if (PyDict_GetItem(u->u_varnames, k) != NULL) { - // Skip cells that are already covered by locals. - numdropped += 1; - continue; - } - int offset = (int)PyLong_AS_LONG(v); - assert(offset >= 0); - offset += nlocals - numdropped; - assert(offset < nlocalsplus); - _Py_set_localsplus_info(offset, k, CO_FAST_CELL, names, kinds); - } - - pos = 0; - while (PyDict_Next(u->u_freevars, &pos, &k, &v)) { - int offset = (int)PyLong_AS_LONG(v); - assert(offset >= 0); - offset += nlocals - numdropped; - assert(offset < nlocalsplus); - _Py_set_localsplus_info(offset, k, CO_FAST_FREE, names, kinds); - } -} - -static PyCodeObject * -makecode(struct compiler_unit *u, struct assembler *a, PyObject *const_cache, - PyObject *constslist, int maxdepth, int nlocalsplus, int code_flags, - PyObject *filename) -{ - PyCodeObject *co = NULL; - PyObject *names = NULL; - PyObject *consts = NULL; - PyObject *localsplusnames = NULL; - PyObject *localspluskinds = NULL; - names = dict_keys_inorder(u->u_names, 0); - if (!names) { - goto error; - } - if (_PyCompile_ConstCacheMergeOne(const_cache, &names) < 0) { - goto error; - } - - consts = PyList_AsTuple(constslist); /* PyCode_New requires a tuple */ - if (consts == NULL) { - goto error; - } - if (_PyCompile_ConstCacheMergeOne(const_cache, &consts) < 0) { - goto error; - } - - assert(u->u_posonlyargcount < INT_MAX); - assert(u->u_argcount < INT_MAX); - assert(u->u_kwonlyargcount < INT_MAX); - int posonlyargcount = (int)u->u_posonlyargcount; - int posorkwargcount = (int)u->u_argcount; - assert(INT_MAX - posonlyargcount - posorkwargcount > 0); - int kwonlyargcount = (int)u->u_kwonlyargcount; - - localsplusnames = PyTuple_New(nlocalsplus); - if (localsplusnames == NULL) { - goto error; - } - localspluskinds = PyBytes_FromStringAndSize(NULL, nlocalsplus); - if (localspluskinds == NULL) { - goto error; - } - compute_localsplus_info(u, nlocalsplus, localsplusnames, localspluskinds); - - struct _PyCodeConstructor con = { - .filename = filename, - .name = u->u_name, - .qualname = u->u_qualname ? u->u_qualname : u->u_name, - .flags = code_flags, - - .code = a->a_bytecode, - .firstlineno = u->u_firstlineno, - .linetable = a->a_linetable, - - .consts = consts, - .names = names, - - .localsplusnames = localsplusnames, - .localspluskinds = localspluskinds, - - .argcount = posonlyargcount + posorkwargcount, - .posonlyargcount = posonlyargcount, - .kwonlyargcount = kwonlyargcount, - - .stacksize = maxdepth, - - .exceptiontable = a->a_except_table, - }; - - if (_PyCode_Validate(&con) < 0) { - goto error; - } - - if (_PyCompile_ConstCacheMergeOne(const_cache, &localsplusnames) < 0) { - goto error; - } - con.localsplusnames = localsplusnames; - - co = _PyCode_New(&con); - if (co == NULL) { - goto error; - } - - error: - Py_XDECREF(names); - Py_XDECREF(consts); - Py_XDECREF(localsplusnames); - Py_XDECREF(localspluskinds); - return co; -} - static int * build_cellfixedoffsets(struct compiler_unit *u) { - int nlocals = (int)PyDict_GET_SIZE(u->u_varnames); - int ncellvars = (int)PyDict_GET_SIZE(u->u_cellvars); - int nfreevars = (int)PyDict_GET_SIZE(u->u_freevars); + int nlocals = (int)PyDict_GET_SIZE(u->u_metadata.u_varnames); + int ncellvars = (int)PyDict_GET_SIZE(u->u_metadata.u_cellvars); + int nfreevars = (int)PyDict_GET_SIZE(u->u_metadata.u_freevars); int noffsets = ncellvars + nfreevars; int *fixed = PyMem_New(int, noffsets); @@ -7211,8 +6624,8 @@ build_cellfixedoffsets(struct compiler_unit *u) PyObject *varname, *cellindex; Py_ssize_t pos = 0; - while (PyDict_Next(u->u_cellvars, &pos, &varname, &cellindex)) { - PyObject *varindex = PyDict_GetItem(u->u_varnames, varname); + while (PyDict_Next(u->u_metadata.u_cellvars, &pos, &varname, &cellindex)) { + PyObject *varindex = PyDict_GetItem(u->u_metadata.u_varnames, varname); if (varindex != NULL) { assert(PyLong_AS_LONG(cellindex) < INT_MAX); assert(PyLong_AS_LONG(varindex) < INT_MAX); @@ -7229,14 +6642,14 @@ static int insert_prefix_instructions(struct compiler_unit *u, basicblock *entryblock, int *fixed, int nfreevars, int code_flags) { - assert(u->u_firstlineno > 0); + assert(u->u_metadata.u_firstlineno > 0); /* Add the generator prefix instructions. */ if (code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { cfg_instr make_gen = { .i_opcode = RETURN_GENERATOR, .i_oparg = 0, - .i_loc = LOCATION(u->u_firstlineno, u->u_firstlineno, -1, -1), + .i_loc = LOCATION(u->u_metadata.u_firstlineno, u->u_metadata.u_firstlineno, -1, -1), .i_target = NULL, }; RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 0, &make_gen)); @@ -7250,12 +6663,12 @@ insert_prefix_instructions(struct compiler_unit *u, basicblock *entryblock, } /* Set up cells for any variable that escapes, to be put in a closure. */ - const int ncellvars = (int)PyDict_GET_SIZE(u->u_cellvars); + const int ncellvars = (int)PyDict_GET_SIZE(u->u_metadata.u_cellvars); if (ncellvars) { - // u->u_cellvars has the cells out of order so we sort them + // u->u_metadata.u_cellvars has the cells out of order so we sort them // before adding the MAKE_CELL instructions. Note that we // adjust for arg cells, which come first. - const int nvars = ncellvars + (int)PyDict_GET_SIZE(u->u_varnames); + const int nvars = ncellvars + (int)PyDict_GET_SIZE(u->u_metadata.u_varnames); int *sorted = PyMem_RawCalloc(nvars, sizeof(int)); if (sorted == NULL) { PyErr_NoMemory(); @@ -7298,9 +6711,9 @@ insert_prefix_instructions(struct compiler_unit *u, basicblock *entryblock, static int fix_cell_offsets(struct compiler_unit *u, basicblock *entryblock, int *fixedmap) { - int nlocals = (int)PyDict_GET_SIZE(u->u_varnames); - int ncellvars = (int)PyDict_GET_SIZE(u->u_cellvars); - int nfreevars = (int)PyDict_GET_SIZE(u->u_freevars); + int nlocals = (int)PyDict_GET_SIZE(u->u_metadata.u_varnames); + int ncellvars = (int)PyDict_GET_SIZE(u->u_metadata.u_cellvars); + int nfreevars = (int)PyDict_GET_SIZE(u->u_metadata.u_freevars); int noffsets = ncellvars + nfreevars; // First deal with duplicates (arg cells). @@ -7344,12 +6757,12 @@ fix_cell_offsets(struct compiler_unit *u, basicblock *entryblock, int *fixedmap) static int prepare_localsplus(struct compiler_unit* u, cfg_builder *g, int code_flags) { - assert(PyDict_GET_SIZE(u->u_varnames) < INT_MAX); - assert(PyDict_GET_SIZE(u->u_cellvars) < INT_MAX); - assert(PyDict_GET_SIZE(u->u_freevars) < INT_MAX); - int nlocals = (int)PyDict_GET_SIZE(u->u_varnames); - int ncellvars = (int)PyDict_GET_SIZE(u->u_cellvars); - int nfreevars = (int)PyDict_GET_SIZE(u->u_freevars); + assert(PyDict_GET_SIZE(u->u_metadata.u_varnames) < INT_MAX); + assert(PyDict_GET_SIZE(u->u_metadata.u_cellvars) < INT_MAX); + assert(PyDict_GET_SIZE(u->u_metadata.u_freevars) < INT_MAX); + int nlocals = (int)PyDict_GET_SIZE(u->u_metadata.u_varnames); + int ncellvars = (int)PyDict_GET_SIZE(u->u_metadata.u_cellvars); + int nfreevars = (int)PyDict_GET_SIZE(u->u_metadata.u_freevars); assert(INT_MAX - nlocals - ncellvars > 0); assert(INT_MAX - nlocals - ncellvars - nfreevars > 0); int nlocalsplus = nlocals + ncellvars + nfreevars; @@ -7389,13 +6802,17 @@ add_return_at_end(struct compiler *c, int addNone) return SUCCESS; } +static int cfg_to_instr_sequence(cfg_builder *g, instr_sequence *seq); static PyCodeObject * -assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, +optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, int code_flags, PyObject *filename) { + instr_sequence optimized_instrs; + memset(&optimized_instrs, 0, sizeof(instr_sequence)); + PyCodeObject *co = NULL; - PyObject *consts = consts_dict_keys_inorder(u->u_consts); + PyObject *consts = consts_dict_keys_inorder(u->u_metadata.u_consts); if (consts == NULL) { goto error; } @@ -7404,25 +6821,18 @@ assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, goto error; } int nparams = (int)PyList_GET_SIZE(u->u_ste->ste_varnames); - int nlocals = (int)PyDict_GET_SIZE(u->u_varnames); - if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, code_flags, nlocals, nparams) < 0) { + int nlocals = (int)PyDict_GET_SIZE(u->u_metadata.u_varnames); + assert(u->u_metadata.u_firstlineno); + if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, code_flags, nlocals, + nparams, u->u_metadata.u_firstlineno) < 0) { goto error; } - /** Assembly **/ - /* Set firstlineno if it wasn't explicitly set. */ - if (!u->u_firstlineno) { - if (g.g_entryblock->b_instr && g.g_entryblock->b_instr->i_loc.lineno) { - u->u_firstlineno = g.g_entryblock->b_instr->i_loc.lineno; - } - else { - u->u_firstlineno = 1; - } - } - if (_PyCfg_ResolveLineNumbers(&g, u->u_firstlineno) < 0) { + if (cfg_to_instr_sequence(&g, &optimized_instrs) < 0) { goto error; } + /** Assembly **/ int nlocalsplus = prepare_localsplus(u, &g, code_flags); if (nlocalsplus < 0) { goto error; @@ -7432,7 +6842,6 @@ assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, if (maxdepth < 0) { goto error; } - /* TO DO -- For 3.12, make sure that `maxdepth <= MAX_ALLOWED_STACK_USE` */ _PyCfg_ConvertExceptionHandlersToNops(g.g_entryblock); @@ -7441,25 +6850,26 @@ assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, if (_PyCfg_ResolveJumps(&g) < 0) { goto error; } + if (cfg_to_instr_sequence(&g, &optimized_instrs) < 0) { + goto error; + } + /* Can't modify the bytecode after computing jump offsets. */ - struct assembler a; - int res = assemble_emit(&a, g.g_entryblock, u->u_firstlineno, const_cache); - if (res == SUCCESS) { - co = makecode(u, &a, const_cache, consts, maxdepth, nlocalsplus, - code_flags, filename); - } - assemble_free(&a); + co = _PyAssemble_MakeCodeObject(&u->u_metadata, const_cache, consts, + maxdepth, g.g_entryblock, nlocalsplus, + code_flags, filename); error: Py_XDECREF(consts); + instr_sequence_fini(&optimized_instrs); _PyCfgBuilder_Fini(&g); return co; } static PyCodeObject * -assemble(struct compiler *c, int addNone) +optimize_and_assemble(struct compiler *c, int addNone) { struct compiler_unit *u = c->u; PyObject *const_cache = c->c_const_cache; @@ -7474,9 +6884,32 @@ assemble(struct compiler *c, int addNone) return NULL; } - return assemble_code_unit(u, const_cache, code_flags, filename); + return optimize_and_assemble_code_unit(u, const_cache, code_flags, filename); } +static int +cfg_to_instr_sequence(cfg_builder *g, instr_sequence *seq) +{ + int lbl = 0; + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + b->b_label = (jump_target_label){lbl}; + lbl += b->b_iused; + } + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + RETURN_IF_ERROR(instr_sequence_use_label(seq, b->b_label.id)); + for (int i = 0; i < b->b_iused; i++) { + cfg_instr *instr = &b->b_instr[i]; + int arg = HAS_TARGET(instr->i_opcode) ? + instr->i_target->b_label.id : + instr->i_oparg; + RETURN_IF_ERROR( + instr_sequence_addop(seq, instr->i_opcode, arg, instr->i_loc)); + } + } + return SUCCESS; +} + + /* Access to compiler optimizations for unit tests. * * _PyCompile_CodeGen takes and AST, applies code-gen and @@ -7492,7 +6925,7 @@ assemble(struct compiler *c, int addNone) */ static int -instructions_to_cfg(PyObject *instructions, cfg_builder *g) +instructions_to_instr_sequence(PyObject *instructions, instr_sequence *seq) { assert(PyList_Check(instructions)); @@ -7526,8 +6959,7 @@ instructions_to_cfg(PyObject *instructions, cfg_builder *g) for (int i = 0; i < num_insts; i++) { if (is_target[i]) { - jump_target_label lbl = {i}; - RETURN_IF_ERROR(_PyCfgBuilder_UseLabel(g, lbl)); + RETURN_IF_ERROR(instr_sequence_use_label(seq, i)); } PyObject *item = PyList_GET_ITEM(instructions, i); if (!PyTuple_Check(item) || PyTuple_GET_SIZE(item) != 6) { @@ -7565,11 +6997,10 @@ instructions_to_cfg(PyObject *instructions, cfg_builder *g) if (PyErr_Occurred()) { goto error; } - RETURN_IF_ERROR(_PyCfgBuilder_Addop(g, opcode, oparg, loc)); + RETURN_IF_ERROR(instr_sequence_addop(seq, opcode, oparg, loc)); } - cfg_instr *last = _PyCfg_BasicblockLastInstr(g->g_curblock); - if (last && !IS_TERMINATOR_OPCODE(last->i_opcode)) { - RETURN_IF_ERROR(_PyCfgBuilder_Addop(g, RETURN_VALUE, 0, NO_LOCATION)); + if (seq->s_used && !IS_TERMINATOR_OPCODE(seq->s_instrs[seq->s_used-1].i_opcode)) { + RETURN_IF_ERROR(instr_sequence_addop(seq, RETURN_VALUE, 0, NO_LOCATION)); } PyMem_Free(is_target); return SUCCESS; @@ -7578,8 +7009,23 @@ instructions_to_cfg(PyObject *instructions, cfg_builder *g) return ERROR; } +static int +instructions_to_cfg(PyObject *instructions, cfg_builder *g) +{ + instr_sequence seq; + memset(&seq, 0, sizeof(instr_sequence)); + + RETURN_IF_ERROR( + instructions_to_instr_sequence(instructions, &seq)); + + RETURN_IF_ERROR(instr_sequence_to_cfg(&seq, g)); + instr_sequence_fini(&seq); + return SUCCESS; +} + static PyObject * -instr_sequence_to_instructions(instr_sequence *seq) { +instr_sequence_to_instructions(instr_sequence *seq) +{ PyObject *instructions = PyList_New(0); if (instructions == NULL) { return NULL; @@ -7709,8 +7155,9 @@ _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts) if (instructions_to_cfg(instructions, &g) < 0) { goto error; } - int code_flags = 0, nlocals = 0, nparams = 0; - if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, code_flags, nlocals, nparams) < 0) { + int code_flags = 0, nlocals = 0, nparams = 0, firstlineno = 1; + if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, code_flags, nlocals, + nparams, firstlineno) < 0) { goto error; } res = cfg_to_instructions(&g); diff --git a/Python/flowgraph.c b/Python/flowgraph.c index cecddbd39c94..d97de0c58771 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -1978,28 +1978,6 @@ push_cold_blocks_to_end(cfg_builder *g, int code_flags) { return SUCCESS; } -int -_PyCfg_OptimizeCodeUnit(cfg_builder *g, PyObject *consts, PyObject *const_cache, - int code_flags, int nlocals, int nparams) -{ - assert(cfg_builder_check(g)); - /** Preprocessing **/ - /* Map labels to targets and mark exception handlers */ - RETURN_IF_ERROR(translate_jump_labels_to_targets(g->g_entryblock)); - RETURN_IF_ERROR(mark_except_handlers(g->g_entryblock)); - RETURN_IF_ERROR(label_exception_targets(g->g_entryblock)); - - /** Optimization **/ - RETURN_IF_ERROR(optimize_cfg(g, consts, const_cache)); - RETURN_IF_ERROR(remove_unused_consts(g->g_entryblock, consts)); - RETURN_IF_ERROR( - add_checks_for_loads_of_uninitialized_variables( - g->g_entryblock, nlocals, nparams)); - - RETURN_IF_ERROR(push_cold_blocks_to_end(g, code_flags)); - return SUCCESS; -} - void _PyCfg_ConvertExceptionHandlersToNops(basicblock *entryblock) { @@ -2149,8 +2127,8 @@ guarantee_lineno_for_exits(basicblock *entryblock, int firstlineno) { } } -int -_PyCfg_ResolveLineNumbers(cfg_builder *g, int firstlineno) +static int +resolve_line_numbers(cfg_builder *g, int firstlineno) { RETURN_IF_ERROR(duplicate_exits_without_lineno(g)); propagate_line_numbers(g->g_entryblock); @@ -2158,3 +2136,25 @@ _PyCfg_ResolveLineNumbers(cfg_builder *g, int firstlineno) return SUCCESS; } +int +_PyCfg_OptimizeCodeUnit(cfg_builder *g, PyObject *consts, PyObject *const_cache, + int code_flags, int nlocals, int nparams, int firstlineno) +{ + assert(cfg_builder_check(g)); + /** Preprocessing **/ + /* Map labels to targets and mark exception handlers */ + RETURN_IF_ERROR(translate_jump_labels_to_targets(g->g_entryblock)); + RETURN_IF_ERROR(mark_except_handlers(g->g_entryblock)); + RETURN_IF_ERROR(label_exception_targets(g->g_entryblock)); + + /** Optimization **/ + RETURN_IF_ERROR(optimize_cfg(g, consts, const_cache)); + RETURN_IF_ERROR(remove_unused_consts(g->g_entryblock, consts)); + RETURN_IF_ERROR( + add_checks_for_loads_of_uninitialized_variables( + g->g_entryblock, nlocals, nparams)); + + RETURN_IF_ERROR(push_cold_blocks_to_end(g, code_flags)); + RETURN_IF_ERROR(resolve_line_numbers(g, firstlineno)); + return SUCCESS; +} From webhook-mailer at python.org Tue Apr 11 06:20:55 2023 From: webhook-mailer at python.org (iritkatriel) Date: Tue, 11 Apr 2023 10:20:55 -0000 Subject: [Python-checkins] gh-91276: remove unused _PyOpcode_RelativeJump (#103156) Message-ID: https://github.com/python/cpython/commit/21bea68e2e97369d808db7d053d4b51b3bc761b9 commit: 21bea68e2e97369d808db7d053d4b51b3bc761b9 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-04-11T11:20:39+01:00 summary: gh-91276: remove unused _PyOpcode_RelativeJump (#103156) files: M Include/internal/pycore_opcode.h M Include/internal/pycore_opcode_utils.h M Python/flowgraph.c M Tools/build/generate_opcode_h.py diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 81ca91465950..f5e9176a3e66 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -12,8 +12,6 @@ extern "C" { #include "opcode.h" -extern const uint32_t _PyOpcode_RelativeJump[9]; - extern const uint32_t _PyOpcode_Jump[9]; extern const uint8_t _PyOpcode_Caches[256]; @@ -21,17 +19,6 @@ extern const uint8_t _PyOpcode_Caches[256]; extern const uint8_t _PyOpcode_Deopt[256]; #ifdef NEED_OPCODE_TABLES -const uint32_t _PyOpcode_RelativeJump[9] = { - 0U, - 0U, - 536870912U, - 135020544U, - 4163U, - 0U, - 0U, - 0U, - 48U, -}; const uint32_t _PyOpcode_Jump[9] = { 0U, 0U, diff --git a/Include/internal/pycore_opcode_utils.h b/Include/internal/pycore_opcode_utils.h index 96bb4d743bf2..1d5ff988290b 100644 --- a/Include/internal/pycore_opcode_utils.h +++ b/Include/internal/pycore_opcode_utils.h @@ -8,7 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#include "pycore_opcode.h" // _PyOpcode_RelativeJump +#include "pycore_opcode.h" // _PyOpcode_Jump #define MAX_REAL_OPCODE 254 @@ -85,9 +85,6 @@ is_bit_set_in_table(const uint32_t *table, int bitindex) { #undef LOG_BITS_PER_INT #undef MASK_LOW_LOG_BITS -#define IS_RELATIVE_JUMP(opcode) (is_bit_set_in_table(_PyOpcode_RelativeJump, opcode)) - - #ifdef __cplusplus } diff --git a/Python/flowgraph.c b/Python/flowgraph.c index d97de0c58771..67cc5c5e88be 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -42,12 +42,6 @@ is_block_push(cfg_instr *i) return IS_BLOCK_PUSH_OPCODE(i->i_opcode); } -static inline int -is_relative_jump(cfg_instr *i) -{ - return IS_RELATIVE_JUMP(i->i_opcode); -} - static inline int is_jump(cfg_instr *i) { @@ -199,8 +193,7 @@ blocksize(basicblock *b) static void dump_instr(cfg_instr *i) { - const char *jrel = (is_relative_jump(i)) ? "jrel " : ""; - const char *jabs = (is_jump(i) && !is_relative_jump(i))? "jabs " : ""; + const char *jump = is_jump(i) ? "jump " : ""; char arg[128]; @@ -211,8 +204,8 @@ dump_instr(cfg_instr *i) if (HAS_TARGET(i->i_opcode)) { sprintf(arg, "target: %p [%d] ", i->i_target, i->i_oparg); } - fprintf(stderr, "line: %d, opcode: %d %s%s%s\n", - i->i_loc.lineno, i->i_opcode, arg, jabs, jrel); + fprintf(stderr, "line: %d, opcode: %d %s%s\n", + i->i_loc.lineno, i->i_opcode, arg, jump); } static inline int @@ -500,25 +493,20 @@ resolve_jump_offsets(basicblock *entryblock) for (int i = 0; i < b->b_iused; i++) { cfg_instr *instr = &b->b_instr[i]; int isize = _PyCfg_InstrSize(instr); - /* Relative jumps are computed relative to - the instruction pointer after fetching - the jump instruction. - */ + /* jump offsets are computed relative to + * the instruction pointer after fetching + * the jump instruction. + */ bsize += isize; if (is_jump(instr)) { instr->i_oparg = instr->i_target->b_offset; - if (is_relative_jump(instr)) { - if (instr->i_oparg < bsize) { - assert(IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); - instr->i_oparg = bsize - instr->i_oparg; - } - else { - assert(!IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); - instr->i_oparg -= bsize; - } + if (instr->i_oparg < bsize) { + assert(IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); + instr->i_oparg = bsize - instr->i_oparg; } else { assert(!IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); + instr->i_oparg -= bsize; } if (_PyCfg_InstrSize(instr) != isize) { extended_arg_recompile = 1; diff --git a/Tools/build/generate_opcode_h.py b/Tools/build/generate_opcode_h.py index 614b17df7409..12fdd3ac84b3 100644 --- a/Tools/build/generate_opcode_h.py +++ b/Tools/build/generate_opcode_h.py @@ -130,12 +130,10 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna for name, op in specialized_opmap.items(): fobj.write(DEFINE.format(name, op)) - iobj.write("\nextern const uint32_t _PyOpcode_RelativeJump[9];\n") iobj.write("\nextern const uint32_t _PyOpcode_Jump[9];\n") iobj.write("\nextern const uint8_t _PyOpcode_Caches[256];\n") iobj.write("\nextern const uint8_t _PyOpcode_Deopt[256];\n") iobj.write("\n#ifdef NEED_OPCODE_TABLES\n") - write_int_array_from_ops("_PyOpcode_RelativeJump", opcode['hasjrel'], iobj) write_int_array_from_ops("_PyOpcode_Jump", opcode['hasjrel'] + opcode['hasjabs'], iobj) iobj.write("\nconst uint8_t _PyOpcode_Caches[256] = {\n") From webhook-mailer at python.org Tue Apr 11 06:25:58 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Tue, 11 Apr 2023 10:25:58 -0000 Subject: [Python-checkins] gh-103373: `__mro_entries__` docs: improve cross references (#103398) Message-ID: https://github.com/python/cpython/commit/e071f00aaefae9eccf787d5c50396c26c8616483 commit: e071f00aaefae9eccf787d5c50396c26c8616483 branch: main author: Alex Waygood committer: AlexWaygood date: 2023-04-11T11:25:45+01:00 summary: gh-103373: `__mro_entries__` docs: improve cross references (#103398) Co-authored-by: C.A.M. Gerlach files: M Doc/library/types.rst M Doc/reference/datamodel.rst diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 747ba58bb225..27b984632591 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -75,9 +75,9 @@ Dynamic Type Creation This function looks for items in *bases* that are not instances of :class:`type`, and returns a tuple where each such object that has - an ``__mro_entries__`` method is replaced with an unpacked result of + an :meth:`~object.__mro_entries__` method is replaced with an unpacked result of calling this method. If a *bases* item is an instance of :class:`type`, - or it doesn't have an ``__mro_entries__`` method, then it is included in + or it doesn't have an :meth:`!__mro_entries__` method, then it is included in the return tuple unchanged. .. versionadded:: 3.7 diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index ed9ebaba784b..9f91ade35e50 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -2089,16 +2089,21 @@ Resolving MRO entries .. method:: object.__mro_entries__(self, bases) If a base that appears in a class definition is not an instance of - :class:`type`, then an ``__mro_entries__`` method is searched on the base. - If an ``__mro_entries__`` method is found, the base is substituted with the - result of a call to ``__mro_entries__`` when creating the class. - The method is called with the original bases tuple, and must return a tuple + :class:`type`, then an :meth:`!__mro_entries__` method is searched on the base. + If an :meth:`!__mro_entries__` method is found, the base is substituted with the + result of a call to :meth:`!__mro_entries__` when creating the class. + The method is called with the original bases tuple + passed to the *bases* parameter, and must return a tuple of classes that will be used instead of the base. The returned tuple may be empty: in these cases, the original base is ignored. .. seealso:: - :pep:`560` - Core support for typing module and generic types + :func:`types.resolve_bases` + Dynamically resolve bases that are not instances of :class:`type`. + + :pep:`560` + Core support for typing module and generic types. Determining the appropriate metaclass From webhook-mailer at python.org Tue Apr 11 06:34:54 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 11 Apr 2023 10:34:54 -0000 Subject: [Python-checkins] gh-103373: `__mro_entries__` docs: improve cross references (GH-103398) Message-ID: https://github.com/python/cpython/commit/07a2851edbf664f2dc87a888fc57315ab53f4b56 commit: 07a2851edbf664f2dc87a888fc57315ab53f4b56 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-11T03:34:46-07:00 summary: gh-103373: `__mro_entries__` docs: improve cross references (GH-103398) (cherry picked from commit e071f00aaefae9eccf787d5c50396c26c8616483) Co-authored-by: Alex Waygood Co-authored-by: C.A.M. Gerlach files: M Doc/library/types.rst M Doc/reference/datamodel.rst diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 3416871c0c1f..daca0ea4318b 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -75,9 +75,9 @@ Dynamic Type Creation This function looks for items in *bases* that are not instances of :class:`type`, and returns a tuple where each such object that has - an ``__mro_entries__`` method is replaced with an unpacked result of + an :meth:`~object.__mro_entries__` method is replaced with an unpacked result of calling this method. If a *bases* item is an instance of :class:`type`, - or it doesn't have an ``__mro_entries__`` method, then it is included in + or it doesn't have an :meth:`!__mro_entries__` method, then it is included in the return tuple unchanged. .. versionadded:: 3.7 diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index b086be26999c..3f0c99cd09eb 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -2088,16 +2088,21 @@ Resolving MRO entries .. method:: object.__mro_entries__(self, bases) If a base that appears in a class definition is not an instance of - :class:`type`, then an ``__mro_entries__`` method is searched on the base. - If an ``__mro_entries__`` method is found, the base is substituted with the - result of a call to ``__mro_entries__`` when creating the class. - The method is called with the original bases tuple, and must return a tuple + :class:`type`, then an :meth:`!__mro_entries__` method is searched on the base. + If an :meth:`!__mro_entries__` method is found, the base is substituted with the + result of a call to :meth:`!__mro_entries__` when creating the class. + The method is called with the original bases tuple + passed to the *bases* parameter, and must return a tuple of classes that will be used instead of the base. The returned tuple may be empty: in these cases, the original base is ignored. .. seealso:: - :pep:`560` - Core support for typing module and generic types + :func:`types.resolve_bases` + Dynamically resolve bases that are not instances of :class:`type`. + + :pep:`560` + Core support for typing module and generic types. Determining the appropriate metaclass From webhook-mailer at python.org Tue Apr 11 06:53:46 2023 From: webhook-mailer at python.org (iritkatriel) Date: Tue, 11 Apr 2023 10:53:46 -0000 Subject: [Python-checkins] gh-77757: replace exception wrapping by PEP-678 notes in typeobject's __set_name__ (#103402) Message-ID: https://github.com/python/cpython/commit/55c99d97e14618dfce41472dd4446f763b0da13f commit: 55c99d97e14618dfce41472dd4446f763b0da13f branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-04-11T11:53:06+01:00 summary: gh-77757: replace exception wrapping by PEP-678 notes in typeobject's __set_name__ (#103402) files: A Misc/NEWS.d/next/Core and Builtins/2023-04-09-22-21-57.gh-issue-77757._Ow-u2.rst M Doc/whatsnew/3.12.rst M Include/internal/pycore_pyerrors.h M Lib/test/test_functools.py M Lib/test/test_subclassinit.py M Objects/typeobject.c M Python/codecs.c M Python/errors.c diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 0eb16367267f..c7fc7d229cd7 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -192,6 +192,10 @@ Other Language Changes * :class:`slice` objects are now hashable, allowing them to be used as dict keys and set items. (Contributed by Will Bradshaw and Furkan Onder in :gh:`101264`.) +* Exceptions raised in a typeobject's ``__set_name__`` method are no longer + wrapped by a :exc:`RuntimeError`. Context information is added to the + exception as a :pep:`678` note. (Contributed by Irit Katriel in :gh:`77757`.) + New Modules =========== diff --git a/Include/internal/pycore_pyerrors.h b/Include/internal/pycore_pyerrors.h index 1bb4a9aa1038..4620a2696449 100644 --- a/Include/internal/pycore_pyerrors.h +++ b/Include/internal/pycore_pyerrors.h @@ -109,6 +109,8 @@ extern PyObject* _Py_Offer_Suggestions(PyObject* exception); PyAPI_FUNC(Py_ssize_t) _Py_UTF8_Edit_Cost(PyObject *str_a, PyObject *str_b, Py_ssize_t max_cost); +void _PyErr_FormatNote(const char *format, ...); + #ifdef __cplusplus } #endif diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index 57db96d37ee3..af286052a7d5 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -2980,7 +2980,7 @@ class MyClass(metaclass=MyMeta): def test_reuse_different_names(self): """Disallow this case because decorated function a would not be cached.""" - with self.assertRaises(RuntimeError) as ctx: + with self.assertRaises(TypeError) as ctx: class ReusedCachedProperty: @py_functools.cached_property def a(self): @@ -2989,7 +2989,7 @@ def a(self): b = a self.assertEqual( - str(ctx.exception.__context__), + str(ctx.exception), str(TypeError("Cannot assign the same cached_property to two different names ('a' and 'b').")) ) diff --git a/Lib/test/test_subclassinit.py b/Lib/test/test_subclassinit.py index 0ad7d17fbd4d..310473a4a2fe 100644 --- a/Lib/test/test_subclassinit.py +++ b/Lib/test/test_subclassinit.py @@ -134,30 +134,28 @@ class Descriptor: def __set_name__(self, owner, name): 1/0 - with self.assertRaises(RuntimeError) as cm: + with self.assertRaises(ZeroDivisionError) as cm: class NotGoingToWork: attr = Descriptor() - exc = cm.exception - self.assertRegex(str(exc), r'\bNotGoingToWork\b') - self.assertRegex(str(exc), r'\battr\b') - self.assertRegex(str(exc), r'\bDescriptor\b') - self.assertIsInstance(exc.__cause__, ZeroDivisionError) + notes = cm.exception.__notes__ + self.assertRegex(str(notes), r'\bNotGoingToWork\b') + self.assertRegex(str(notes), r'\battr\b') + self.assertRegex(str(notes), r'\bDescriptor\b') def test_set_name_wrong(self): class Descriptor: def __set_name__(self): pass - with self.assertRaises(RuntimeError) as cm: + with self.assertRaises(TypeError) as cm: class NotGoingToWork: attr = Descriptor() - exc = cm.exception - self.assertRegex(str(exc), r'\bNotGoingToWork\b') - self.assertRegex(str(exc), r'\battr\b') - self.assertRegex(str(exc), r'\bDescriptor\b') - self.assertIsInstance(exc.__cause__, TypeError) + notes = cm.exception.__notes__ + self.assertRegex(str(notes), r'\bNotGoingToWork\b') + self.assertRegex(str(notes), r'\battr\b') + self.assertRegex(str(notes), r'\bDescriptor\b') def test_set_name_lookup(self): resolved = [] diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-09-22-21-57.gh-issue-77757._Ow-u2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-09-22-21-57.gh-issue-77757._Ow-u2.rst new file mode 100644 index 000000000000..85c8ecf7de8d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-09-22-21-57.gh-issue-77757._Ow-u2.rst @@ -0,0 +1,3 @@ +Exceptions raised in a typeobject's ``__set_name__`` method are no longer +wrapped by a :exc:`RuntimeError`. Context information is added to the +exception as a :pep:`678` note. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 995547e7915f..9ea458f30394 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -9137,13 +9137,15 @@ type_new_set_names(PyTypeObject *type) Py_DECREF(set_name); if (res == NULL) { - _PyErr_FormatFromCause(PyExc_RuntimeError, + _PyErr_FormatNote( "Error calling __set_name__ on '%.100s' instance %R " "in '%.100s'", Py_TYPE(value)->tp_name, key, type->tp_name); goto error; } - Py_DECREF(res); + else { + Py_DECREF(res); + } } Py_DECREF(names_to_set); diff --git a/Python/codecs.c b/Python/codecs.c index 9d800f9856c2..1983f56ba204 100644 --- a/Python/codecs.c +++ b/Python/codecs.c @@ -11,6 +11,7 @@ Copyright (c) Corporation for National Research Initiatives. #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_interp.h" // PyInterpreterState.codec_search_path +#include "pycore_pyerrors.h" // _PyErr_FormatNote() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI #include @@ -382,29 +383,6 @@ PyObject *PyCodec_StreamWriter(const char *encoding, return codec_getstreamcodec(encoding, stream, errors, 3); } -static void -add_note_to_codec_error(const char *operation, - const char *encoding) -{ - PyObject *exc = PyErr_GetRaisedException(); - if (exc == NULL) { - return; - } - PyObject *note = PyUnicode_FromFormat("%s with '%s' codec failed", - operation, encoding); - if (note == NULL) { - _PyErr_ChainExceptions1(exc); - return; - } - int res = _PyException_AddNote(exc, note); - Py_DECREF(note); - if (res < 0) { - _PyErr_ChainExceptions1(exc); - return; - } - PyErr_SetRaisedException(exc); -} - /* Encode an object (e.g. a Unicode object) using the given encoding and return the resulting encoded object (usually a Python string). @@ -425,7 +403,7 @@ _PyCodec_EncodeInternal(PyObject *object, result = PyObject_Call(encoder, args, NULL); if (result == NULL) { - add_note_to_codec_error("encoding", encoding); + _PyErr_FormatNote("%s with '%s' codec failed", "encoding", encoding); goto onError; } @@ -470,7 +448,7 @@ _PyCodec_DecodeInternal(PyObject *object, result = PyObject_Call(decoder, args, NULL); if (result == NULL) { - add_note_to_codec_error("decoding", encoding); + _PyErr_FormatNote("%s with '%s' codec failed", "decoding", encoding); goto onError; } if (!PyTuple_Check(result) || diff --git a/Python/errors.c b/Python/errors.c index ab14770c6e81..0ff6a0d5985f 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -1200,6 +1200,33 @@ PyErr_Format(PyObject *exception, const char *format, ...) } +/* Adds a note to the current exception (if any) */ +void +_PyErr_FormatNote(const char *format, ...) +{ + PyObject *exc = PyErr_GetRaisedException(); + if (exc == NULL) { + return; + } + va_list vargs; + va_start(vargs, format); + PyObject *note = PyUnicode_FromFormatV(format, vargs); + va_end(vargs); + if (note == NULL) { + goto error; + } + int res = _PyException_AddNote(exc, note); + Py_DECREF(note); + if (res < 0) { + goto error; + } + PyErr_SetRaisedException(exc); + return; +error: + _PyErr_ChainExceptions1(exc); +} + + PyObject * PyErr_NewException(const char *name, PyObject *base, PyObject *dict) { From webhook-mailer at python.org Tue Apr 11 09:50:32 2023 From: webhook-mailer at python.org (hugovk) Date: Tue, 11 Apr 2023 13:50:32 -0000 Subject: [Python-checkins] gh-87864: Use correct function definition syntax in the docs (#103312) Message-ID: https://github.com/python/cpython/commit/50b4b1598411ed393f47ce7f4fffbe5b9063cd42 commit: 50b4b1598411ed393f47ce7f4fffbe5b9063cd42 branch: main author: Nikita Sobolev committer: hugovk date: 2023-04-11T16:50:25+03:00 summary: gh-87864: Use correct function definition syntax in the docs (#103312) files: M Doc/glossary.rst M Doc/library/functions.rst M Lib/abc.py M Objects/funcobject.c diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 3d74d550dc34..53e8cdcae1cd 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -214,7 +214,7 @@ Glossary A callable is an object that can be called, possibly with a set of arguments (see :term:`argument`), with the following syntax:: - callable(argument1, argument2, ...) + callable(argument1, argument2, argumentN) A :term:`function`, and by extension a :term:`method`, is a callable. An instance of a class that implements the :meth:`~object.__call__` diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 8797485cd05d..7792e598c115 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1681,7 +1681,7 @@ are always available. They are listed here in alphabetical order. class C: @staticmethod - def f(arg1, arg2, ...): ... + def f(arg1, arg2, argN): ... The ``@staticmethod`` form is a function :term:`decorator` -- see :ref:`function` for details. diff --git a/Lib/abc.py b/Lib/abc.py index 42048ddb8553..f8a4e11ce9c3 100644 --- a/Lib/abc.py +++ b/Lib/abc.py @@ -18,7 +18,7 @@ class that has a metaclass derived from ABCMeta cannot be class C(metaclass=ABCMeta): @abstractmethod - def my_abstract_method(self, ...): + def my_abstract_method(self, arg1, arg2, argN): ... """ funcobj.__isabstractmethod__ = True diff --git a/Objects/funcobject.c b/Objects/funcobject.c index ce5d7bda32c0..78c1144afca2 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -942,7 +942,7 @@ functools_wraps(PyObject *wrapper, PyObject *wrapped) class C: @classmethod - def f(cls, arg1, arg2, ...): + def f(cls, arg1, arg2, argN): ... It can be called either on the class (e.g. C.f()) or on an instance @@ -1066,7 +1066,7 @@ To declare a class method, use this idiom:\n\ \n\ class C:\n\ @classmethod\n\ - def f(cls, arg1, arg2, ...):\n\ + def f(cls, arg1, arg2, argN):\n\ ...\n\ \n\ It can be called either on the class (e.g. C.f()) or on an instance\n\ @@ -1138,7 +1138,7 @@ PyClassMethod_New(PyObject *callable) class C: @staticmethod - def f(arg1, arg2, ...): + def f(arg1, arg2, argN): ... It can be called either on the class (e.g. C.f()) or on an instance @@ -1260,7 +1260,7 @@ To declare a static method, use this idiom:\n\ \n\ class C:\n\ @staticmethod\n\ - def f(arg1, arg2, ...):\n\ + def f(arg1, arg2, argN):\n\ ...\n\ \n\ It can be called either on the class (e.g. C.f()) or on an instance\n\ From webhook-mailer at python.org Tue Apr 11 10:19:41 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 11 Apr 2023 14:19:41 -0000 Subject: [Python-checkins] gh-87864: Use correct function definition syntax in the docs (GH-103312) Message-ID: https://github.com/python/cpython/commit/e715da6db1d1d70cd779dc48e1ba8110c51cc1bf commit: e715da6db1d1d70cd779dc48e1ba8110c51cc1bf branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-11T07:19:33-07:00 summary: gh-87864: Use correct function definition syntax in the docs (GH-103312) (cherry picked from commit 50b4b1598411ed393f47ce7f4fffbe5b9063cd42) Co-authored-by: Nikita Sobolev files: M Doc/glossary.rst M Doc/library/functions.rst M Lib/abc.py M Objects/funcobject.c diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 3d74d550dc34..53e8cdcae1cd 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -214,7 +214,7 @@ Glossary A callable is an object that can be called, possibly with a set of arguments (see :term:`argument`), with the following syntax:: - callable(argument1, argument2, ...) + callable(argument1, argument2, argumentN) A :term:`function`, and by extension a :term:`method`, is a callable. An instance of a class that implements the :meth:`~object.__call__` diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 2ce3860440be..1c3deb2e78c7 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1677,7 +1677,7 @@ are always available. They are listed here in alphabetical order. class C: @staticmethod - def f(arg1, arg2, ...): ... + def f(arg1, arg2, argN): ... The ``@staticmethod`` form is a function :term:`decorator` -- see :ref:`function` for details. diff --git a/Lib/abc.py b/Lib/abc.py index 42048ddb8553..f8a4e11ce9c3 100644 --- a/Lib/abc.py +++ b/Lib/abc.py @@ -18,7 +18,7 @@ class that has a metaclass derived from ABCMeta cannot be class C(metaclass=ABCMeta): @abstractmethod - def my_abstract_method(self, ...): + def my_abstract_method(self, arg1, arg2, argN): ... """ funcobj.__isabstractmethod__ = True diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 57600c97e6aa..3a0553261bf1 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -845,7 +845,7 @@ functools_wraps(PyObject *wrapper, PyObject *wrapped) class C: @classmethod - def f(cls, arg1, arg2, ...): + def f(cls, arg1, arg2, argN): ... It can be called either on the class (e.g. C.f()) or on an instance @@ -970,7 +970,7 @@ To declare a class method, use this idiom:\n\ \n\ class C:\n\ @classmethod\n\ - def f(cls, arg1, arg2, ...):\n\ + def f(cls, arg1, arg2, argN):\n\ ...\n\ \n\ It can be called either on the class (e.g. C.f()) or on an instance\n\ @@ -1043,7 +1043,7 @@ PyClassMethod_New(PyObject *callable) class C: @staticmethod - def f(arg1, arg2, ...): + def f(arg1, arg2, argN): ... It can be called either on the class (e.g. C.f()) or on an instance @@ -1167,7 +1167,7 @@ To declare a static method, use this idiom:\n\ \n\ class C:\n\ @staticmethod\n\ - def f(arg1, arg2, ...):\n\ + def f(arg1, arg2, argN):\n\ ...\n\ \n\ It can be called either on the class (e.g. C.f()) or on an instance\n\ From webhook-mailer at python.org Tue Apr 11 12:26:53 2023 From: webhook-mailer at python.org (barneygale) Date: Tue, 11 Apr 2023 16:26:53 -0000 Subject: [Python-checkins] GH-103220: Fix `ntpath.join()` of partial UNC drive with trailing slash (GH-103221) Message-ID: https://github.com/python/cpython/commit/b57105ae33e1f61e6bdf0eec45c4135d067b9b22 commit: b57105ae33e1f61e6bdf0eec45c4135d067b9b22 branch: main author: Barney Gale committer: barneygale date: 2023-04-11T17:26:45+01:00 summary: GH-103220: Fix `ntpath.join()` of partial UNC drive with trailing slash (GH-103221) files: A Misc/NEWS.d/next/Library/2023-04-03-21-08-53.gh-issue-103220.OW_Bj5.rst M Lib/ntpath.py M Lib/test/test_ntpath.py diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 6e2da79c85d3..0f3674fe11ee 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -142,7 +142,7 @@ def join(path, *paths): result_path = result_path + p_path ## add separator between UNC and non-absolute path if (result_path and not result_root and - result_drive and result_drive[-1:] != colon): + result_drive and result_drive[-1:] not in colon + seps): return result_drive + sep + result_path return result_drive + result_root + result_path except (TypeError, AttributeError, BytesWarning): diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index 4e755d154039..42b9587ca181 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -300,6 +300,11 @@ def test_join(self): tester("ntpath.join('//computer/share', 'a', 'b')", '//computer/share\\a\\b') tester("ntpath.join('//computer/share', 'a/b')", '//computer/share\\a/b') + tester("ntpath.join('\\\\', 'computer')", '\\\\computer') + tester("ntpath.join('\\\\computer\\', 'share')", '\\\\computer\\share') + tester("ntpath.join('\\\\computer\\share\\', 'a')", '\\\\computer\\share\\a') + tester("ntpath.join('\\\\computer\\share\\a\\', 'b')", '\\\\computer\\share\\a\\b') + def test_normpath(self): tester("ntpath.normpath('A//////././//.//B')", r'A\B') tester("ntpath.normpath('A/./B')", r'A\B') diff --git a/Misc/NEWS.d/next/Library/2023-04-03-21-08-53.gh-issue-103220.OW_Bj5.rst b/Misc/NEWS.d/next/Library/2023-04-03-21-08-53.gh-issue-103220.OW_Bj5.rst new file mode 100644 index 000000000000..9cf26c26873b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-03-21-08-53.gh-issue-103220.OW_Bj5.rst @@ -0,0 +1,2 @@ +Fix issue where :func:`os.path.join` added a slash when joining onto an +incomplete UNC drive with a trailing slash on Windows. From webhook-mailer at python.org Tue Apr 11 15:20:54 2023 From: webhook-mailer at python.org (zooba) Date: Tue, 11 Apr 2023 19:20:54 -0000 Subject: [Python-checkins] gh-103088: Sanitize venv paths when using MSYS or Cygwin Bash (GH-103325) Message-ID: https://github.com/python/cpython/commit/ebc81034278ea186b4110c7dbf6d1c2a0ada9398 commit: ebc81034278ea186b4110c7dbf6d1c2a0ada9398 branch: main author: Stanislav Syekirin committer: zooba date: 2023-04-11T20:20:46+01:00 summary: gh-103088: Sanitize venv paths when using MSYS or Cygwin Bash (GH-103325) files: A Misc/NEWS.d/next/Windows/2023-04-11-09-22-22.gh-issue-103088.6AJEuR.rst M Lib/venv/scripts/common/activate M PCbuild/find_python.bat diff --git a/Lib/venv/scripts/common/activate b/Lib/venv/scripts/common/activate index 6fbc2b8801da..cb898b39670c 100644 --- a/Lib/venv/scripts/common/activate +++ b/Lib/venv/scripts/common/activate @@ -38,8 +38,15 @@ deactivate () { # unset irrelevant variables deactivate nondestructive -VIRTUAL_ENV="__VENV_DIR__" -export VIRTUAL_ENV +# on Windows, a path can contain colons and backslashes and has to be converted: +if [ "$OSTYPE" = "cygwin" ] || [ "$OSTYPE" = "msys" ] ; then + # transform D:\path\to\venv to /d/path/to/venv on MSYS + # and to /cygdrive/d/path/to/venv on Cygwin + export VIRTUAL_ENV=$(cygpath "__VENV_DIR__") +else + # use the path as-is + export VIRTUAL_ENV="__VENV_DIR__" +fi _OLD_VIRTUAL_PATH="$PATH" PATH="$VIRTUAL_ENV/__VENV_BIN_NAME__:$PATH" diff --git a/Misc/NEWS.d/next/Windows/2023-04-11-09-22-22.gh-issue-103088.6AJEuR.rst b/Misc/NEWS.d/next/Windows/2023-04-11-09-22-22.gh-issue-103088.6AJEuR.rst new file mode 100644 index 000000000000..f9f5343f4210 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-04-11-09-22-22.gh-issue-103088.6AJEuR.rst @@ -0,0 +1 @@ +Fixes venvs not working in bash on Windows across different disks diff --git a/PCbuild/find_python.bat b/PCbuild/find_python.bat index 11d6cba7a172..7af5503d80a0 100644 --- a/PCbuild/find_python.bat +++ b/PCbuild/find_python.bat @@ -42,7 +42,7 @@ @if NOT "%HOST_PYTHON%"=="" @%HOST_PYTHON% -Ec "import sys; assert sys.version_info[:2] >= (3, 9)" >nul 2>nul && (set PYTHON="%HOST_PYTHON%") && (set _Py_Python_Source=found as HOST_PYTHON) && goto :found @rem If py.exe finds a recent enough version, use that one - at for %%p in (3.10 3.9) do @py -%%p -EV >nul 2>&1 && (set PYTHON=py -%%p) && (set _Py_Python_Source=found %%p with py.exe) && goto :found + at for %%p in (3.11 3.10 3.9) do @py -%%p -EV >nul 2>&1 && (set PYTHON=py -%%p) && (set _Py_Python_Source=found %%p with py.exe) && goto :found @if NOT exist "%_Py_EXTERNALS_DIR%" mkdir "%_Py_EXTERNALS_DIR%" @set _Py_NUGET=%NUGET% From webhook-mailer at python.org Tue Apr 11 16:08:36 2023 From: webhook-mailer at python.org (iritkatriel) Date: Tue, 11 Apr 2023 20:08:36 -0000 Subject: [Python-checkins] gh-87092: fix refleak in peepholer test harness (#103448) Message-ID: https://github.com/python/cpython/commit/9db2db4fa4bc2a955170f727fde68ff4a4de3080 commit: 9db2db4fa4bc2a955170f727fde68ff4a4de3080 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-04-11T21:08:29+01:00 summary: gh-87092: fix refleak in peepholer test harness (#103448) files: M Python/compile.c diff --git a/Python/compile.c b/Python/compile.c index 15fca8296c69..3e152060d2f1 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7148,10 +7148,6 @@ _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts) } cfg_builder g; - memset(&g, 0, sizeof(cfg_builder)); - if (_PyCfgBuilder_Init(&g) < 0) { - goto error; - } if (instructions_to_cfg(instructions, &g) < 0) { goto error; } From webhook-mailer at python.org Tue Apr 11 16:30:12 2023 From: webhook-mailer at python.org (benjaminp) Date: Tue, 11 Apr 2023 20:30:12 -0000 Subject: [Python-checkins] Remove redundant words from interpreter_definition.md. (GH-103455) Message-ID: https://github.com/python/cpython/commit/96663875b2ea55c65e83551cdb741bbcdcaa7f21 commit: 96663875b2ea55c65e83551cdb741bbcdcaa7f21 branch: main author: Benjamin Peterson committer: benjaminp date: 2023-04-11T15:30:05-05:00 summary: Remove redundant words from interpreter_definition.md. (GH-103455) files: M Tools/cases_generator/interpreter_definition.md diff --git a/Tools/cases_generator/interpreter_definition.md b/Tools/cases_generator/interpreter_definition.md index c7bd38d32ff4..6f902f60c68e 100644 --- a/Tools/cases_generator/interpreter_definition.md +++ b/Tools/cases_generator/interpreter_definition.md @@ -137,9 +137,9 @@ The following definitions may occur: `foo_1` is legal. `$` is not legal, nor is `struct` or `class`. The optional `type` in an `object` is the C type. It defaults to `PyObject *`. -The objects before the "--" are the objects on top of the the stack at the start -of the instruction. Those after the "--" are the objects on top of the the stack -at the end of the instruction. +The objects before the "--" are the objects on top of the stack at the start of +the instruction. Those after the "--" are the objects on top of the stack at the +end of the instruction. An `inst` without `stack_effect` is a transitional form to allow the original C code definitions to be copied. It lacks information to generate anything other than the From webhook-mailer at python.org Tue Apr 11 18:40:37 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 11 Apr 2023 22:40:37 -0000 Subject: [Python-checkins] gh-103143: Polish pdb help messages and doc strings (GH-103144) Message-ID: https://github.com/python/cpython/commit/2f41a009b7311a4b44bae5b3583cde3d6d10d8d1 commit: 2f41a009b7311a4b44bae5b3583cde3d6d10d8d1 branch: main author: Tian Gao committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-11T15:40:30-07:00 summary: gh-103143: Polish pdb help messages and doc strings (GH-103144) * Made all the command part of the docstring match the official documentation * Always have a space between the command and the description in docstring * Added a helper function to format the help message Before: ``` (Pdb) h a a(rgs) Print the argument list of the current function. (Pdb) h commands commands [bpnumber] (com) ... (com) end (Pdb) ... (Pdb) h interact interact Start an interactive interpreter whose global namespace contains all the (global and local) names found in the current scope. ``` After ``` (Pdb) h a Usage: a(rgs) Print the argument list of the current function. (Pdb) h commands Usage: (Pdb) commands [bpnumber] (com) ... (com) end (Pdb) ... (Pdb) h interact Usage: interact Start an interactive interpreter whose global namespace contains all the (global and local) names found in the current scope. ``` Automerge-Triggered-By: GH:brandtbucher files: A Misc/NEWS.d/next/Library/2023-03-31-01-13-00.gh-issue-103143.6eMluy.rst M Doc/library/pdb.rst M Lib/pdb.py diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index d80c5eebbf27..4170882efef1 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -315,14 +315,14 @@ can be overridden by the local file. With a space separated list of breakpoint numbers, clear those breakpoints. Without argument, clear all breaks (but first ask confirmation). -.. pdbcommand:: disable [bpnumber ...] +.. pdbcommand:: disable bpnumber [bpnumber ...] Disable the breakpoints given as a space separated list of breakpoint numbers. Disabling a breakpoint means it cannot cause the program to stop execution, but unlike clearing a breakpoint, it remains in the list of breakpoints and can be (re-)enabled. -.. pdbcommand:: enable [bpnumber ...] +.. pdbcommand:: enable bpnumber [bpnumber ...] Enable the breakpoints specified. diff --git a/Lib/pdb.py b/Lib/pdb.py index e03142e9b5d8..a3553b345a8d 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -586,7 +586,7 @@ def _complete_expression(self, text, line, begidx, endidx): # Return true to exit from the command loop def do_commands(self, arg): - """commands [bpnumber] + """(Pdb) commands [bpnumber] (com) ... (com) end (Pdb) @@ -672,6 +672,7 @@ def do_commands(self, arg): def do_break(self, arg, temporary = 0): """b(reak) [ ([filename:]lineno | function) [, condition] ] + Without argument, list all breaks. With a line number argument, set a break at this line in the @@ -780,6 +781,7 @@ def defaultFile(self): def do_tbreak(self, arg): """tbreak [ ([filename:]lineno | function) [, condition] ] + Same arguments as break, but sets a temporary breakpoint: it is automatically deleted when first hit. """ @@ -844,6 +846,7 @@ def checkline(self, filename, lineno): def do_enable(self, arg): """enable bpnumber [bpnumber ...] + Enables the breakpoints given as a space separated list of breakpoint numbers. """ @@ -861,6 +864,7 @@ def do_enable(self, arg): def do_disable(self, arg): """disable bpnumber [bpnumber ...] + Disables the breakpoints given as a space separated list of breakpoint numbers. Disabling a breakpoint means it cannot cause the program to stop execution, but unlike clearing a @@ -881,6 +885,7 @@ def do_disable(self, arg): def do_condition(self, arg): """condition bpnumber [condition] + Set a new condition for the breakpoint, an expression which must evaluate to true before the breakpoint is honored. If condition is absent, any existing condition is removed; i.e., @@ -911,6 +916,7 @@ def do_condition(self, arg): def do_ignore(self, arg): """ignore bpnumber [count] + Set the ignore count for the given breakpoint number. If count is omitted, the ignore count is set to 0. A breakpoint becomes active when the ignore count is zero. When non-zero, @@ -945,7 +951,8 @@ def do_ignore(self, arg): complete_ignore = _complete_bpnumber def do_clear(self, arg): - """cl(ear) filename:lineno\ncl(ear) [bpnumber [bpnumber...]] + """cl(ear) [filename:lineno | bpnumber ...] + With a space separated list of breakpoint numbers, clear those breakpoints. Without argument, clear all breaks (but first ask confirmation). With a filename:lineno argument, @@ -997,6 +1004,7 @@ def do_clear(self, arg): def do_where(self, arg): """w(here) + Print a stack trace, with the most recent frame at the bottom. An arrow indicates the "current frame", which determines the context of most commands. 'bt' is an alias for this command. @@ -1015,6 +1023,7 @@ def _select_frame(self, number): def do_up(self, arg): """u(p) [count] + Move the current frame count (default one) levels up in the stack trace (to an older frame). """ @@ -1035,6 +1044,7 @@ def do_up(self, arg): def do_down(self, arg): """d(own) [count] + Move the current frame count (default one) levels down in the stack trace (to a newer frame). """ @@ -1055,6 +1065,7 @@ def do_down(self, arg): def do_until(self, arg): """unt(il) [lineno] + Without argument, continue execution until the line with a number greater than the current one is reached. With a line number, continue execution until a line with a number greater @@ -1079,6 +1090,7 @@ def do_until(self, arg): def do_step(self, arg): """s(tep) + Execute the current line, stop at the first possible occasion (either in a function that is called or in the current function). @@ -1089,6 +1101,7 @@ def do_step(self, arg): def do_next(self, arg): """n(ext) + Continue execution until the next line in the current function is reached or it returns. """ @@ -1098,6 +1111,7 @@ def do_next(self, arg): def do_run(self, arg): """run [args...] + Restart the debugged python program. If a string is supplied it is split with "shlex", and the result is used as the new sys.argv. History, breakpoints, actions and debugger options @@ -1119,6 +1133,7 @@ def do_run(self, arg): def do_return(self, arg): """r(eturn) + Continue execution until the current function returns. """ self.set_return(self.curframe) @@ -1127,6 +1142,7 @@ def do_return(self, arg): def do_continue(self, arg): """c(ont(inue)) + Continue execution, only stop when a breakpoint is encountered. """ if not self.nosigint: @@ -1145,6 +1161,7 @@ def do_continue(self, arg): def do_jump(self, arg): """j(ump) lineno + Set the next line that will be executed. Only available in the bottom-most frame. This lets you jump back and execute code again, or jump forward to skip code that you don't want @@ -1174,6 +1191,7 @@ def do_jump(self, arg): def do_debug(self, arg): """debug code + Enter a recursive debugger that steps through the code argument (which is an arbitrary expression or statement to be executed in the current environment). @@ -1195,7 +1213,8 @@ def do_debug(self, arg): complete_debug = _complete_expression def do_quit(self, arg): - """q(uit)\nexit + """q(uit) | exit + Quit from the debugger. The program being executed is aborted. """ self._user_requested_quit = True @@ -1207,6 +1226,7 @@ def do_quit(self, arg): def do_EOF(self, arg): """EOF + Handles the receipt of EOF as a command. """ self.message('') @@ -1216,6 +1236,7 @@ def do_EOF(self, arg): def do_args(self, arg): """a(rgs) + Print the argument list of the current function. """ co = self.curframe.f_code @@ -1233,6 +1254,7 @@ def do_args(self, arg): def do_retval(self, arg): """retval + Print the return value for the last return of a function. """ if '__return__' in self.curframe_locals: @@ -1273,12 +1295,14 @@ def _msg_val_func(self, arg, func): def do_p(self, arg): """p expression + Print the value of the expression. """ self._msg_val_func(arg, repr) def do_pp(self, arg): """pp expression + Pretty-print the value of the expression. """ self._msg_val_func(arg, pprint.pformat) @@ -1288,7 +1312,7 @@ def do_pp(self, arg): complete_pp = _complete_expression def do_list(self, arg): - """l(ist) [first [,last] | .] + """l(ist) [first[, last] | .] List source code for the current file. Without arguments, list 11 lines around the current line or continue the previous @@ -1345,7 +1369,8 @@ def do_list(self, arg): do_l = do_list def do_longlist(self, arg): - """longlist | ll + """ll | longlist + List the whole source code for the current function or frame. """ filename = self.curframe.f_code.co_filename @@ -1360,6 +1385,7 @@ def do_longlist(self, arg): def do_source(self, arg): """source expression + Try to get source code for the given object and display it. """ try: @@ -1397,7 +1423,8 @@ def _print_lines(self, lines, start, breaks=(), frame=None): self.message(s + '\t' + line.rstrip()) def do_whatis(self, arg): - """whatis arg + """whatis expression + Print the type of the argument. """ try: @@ -1485,7 +1512,8 @@ def do_interact(self, arg): code.interact("*interactive*", local=ns) def do_alias(self, arg): - """alias [name [command [parameter parameter ...] ]] + """alias [name [command]] + Create an alias called 'name' that executes 'command'. The command must *not* be enclosed in quotes. Replaceable parameters can be indicated by %1, %2, and so on, while %* is @@ -1521,6 +1549,7 @@ def do_alias(self, arg): def do_unalias(self, arg): """unalias name + Delete the specified alias. """ args = arg.split() @@ -1563,6 +1592,7 @@ def print_stack_entry(self, frame_lineno, prompt_prefix=line_prefix): def do_help(self, arg): """h(elp) + Without argument, print the list of available commands. With a command name as argument, print help about that command. "help pdb" shows the full pdb documentation. @@ -1586,12 +1616,13 @@ def do_help(self, arg): if command.__doc__ is None: self.error('No help for %r; __doc__ string missing' % arg) return - self.message(command.__doc__.rstrip()) + self.message(self._help_message_from_doc(command.__doc__)) do_h = do_help def help_exec(self): """(!) statement + Execute the (one-line) statement in the context of the current stack frame. The exclamation point can be omitted unless the first word of the statement resembles a debugger command. To @@ -1672,6 +1703,26 @@ def _getsourcelines(self, obj): lineno = max(1, lineno) return lines, lineno + def _help_message_from_doc(self, doc): + lines = [line.strip() for line in doc.rstrip().splitlines()] + if not lines: + return "No help message found." + if "" in lines: + usage_end = lines.index("") + else: + usage_end = 1 + formatted = [] + indent = " " * len(self.prompt) + for i, line in enumerate(lines): + if i == 0: + prefix = "Usage: " + elif i < usage_end: + prefix = " " + else: + prefix = "" + formatted.append(indent + prefix + line) + return "\n".join(formatted) + # Collect all command help into docstring, if not run with -OO if __doc__ is not None: diff --git a/Misc/NEWS.d/next/Library/2023-03-31-01-13-00.gh-issue-103143.6eMluy.rst b/Misc/NEWS.d/next/Library/2023-03-31-01-13-00.gh-issue-103143.6eMluy.rst new file mode 100644 index 000000000000..32bd62d27c7c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-31-01-13-00.gh-issue-103143.6eMluy.rst @@ -0,0 +1 @@ +Polish the help messages and docstrings of :mod:`pdb`. From webhook-mailer at python.org Wed Apr 12 02:18:47 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Wed, 12 Apr 2023 06:18:47 -0000 Subject: [Python-checkins] gh-103237: Polish pdb docs (#103238) Message-ID: https://github.com/python/cpython/commit/449bf2a76b23b97a38158d506bc30d3ebe006321 commit: 449bf2a76b23b97a38158d506bc30d3ebe006321 branch: main author: Tian Gao committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-04-11T23:18:34-07:00 summary: gh-103237: Polish pdb docs (#103238) files: M Doc/library/pdb.rst diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 4170882efef1..5bc48a6d5f77 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -36,73 +36,91 @@ extension interface uses the modules :mod:`bdb` and :mod:`cmd`. Module :mod:`traceback` Standard interface to extract, format and print stack traces of Python programs. -The debugger's prompt is ``(Pdb)``. Typical usage to run a program under control -of the debugger is:: +The typical usage to break into the debugger is to insert:: - >>> import pdb - >>> import mymodule - >>> pdb.run('mymodule.test()') - > (0)?() - (Pdb) continue - > (1)?() + import pdb; pdb.set_trace() + +Or:: + + breakpoint() + +at the location you want to break into the debugger, and then run the program. +You can then step through the code following this statement, and continue +running without the debugger using the :pdbcmd:`continue` command. + +.. versionadded:: 3.7 + The built-in :func:`breakpoint()`, when called with defaults, can be used + instead of ``import pdb; pdb.set_trace()``. + +:: + + def double(x): + breakpoint() + return x * 2 + val = 3 + print(f"{val} * 2 is {double(val)}") + +The debugger's prompt is ``(Pdb)``, which is the indicator that you are in debug mode:: + + > ...(3)double() + -> return x * 2 + (Pdb) p x + 3 (Pdb) continue - NameError: 'spam' - > (1)?() - (Pdb) + 3 * 2 is 6 .. versionchanged:: 3.3 Tab-completion via the :mod:`readline` module is available for commands and command arguments, e.g. the current global and local names are offered as arguments of the ``p`` command. -:file:`pdb.py` can also be invoked as a script to debug other scripts. For + +You can also invoke :mod:`pdb` from the command line to debug other scripts. For example:: python -m pdb myscript.py -When invoked as a script, pdb will automatically enter post-mortem debugging if +When invoked as a module, pdb will automatically enter post-mortem debugging if the program being debugged exits abnormally. After post-mortem debugging (or after normal exit of the program), pdb will restart the program. Automatic restarting preserves pdb's state (such as breakpoints) and in most cases is more useful than quitting the debugger upon program's exit. .. versionadded:: 3.2 - :file:`pdb.py` now accepts a ``-c`` option that executes commands as if given + ``-c`` option is introduced to execute commands as if given in a :file:`.pdbrc` file, see :ref:`debugger-commands`. .. versionadded:: 3.7 - :file:`pdb.py` now accepts a ``-m`` option that execute modules similar to the way + ``-m`` option is introduced to execute modules similar to the way ``python -m`` does. As with a script, the debugger will pause execution just before the first line of the module. +Typical usage to execute a statement under control of the debugger is:: -The typical usage to break into the debugger is to insert:: - - import pdb; pdb.set_trace() - -at the location you want to break into the debugger, and then run the program. -You can then step through the code following this statement, and continue -running without the debugger using the :pdbcmd:`continue` command. - -.. versionadded:: 3.7 - The built-in :func:`breakpoint()`, when called with defaults, can be used - instead of ``import pdb; pdb.set_trace()``. + >>> import pdb + >>> def f(x): + ... print(1 / x) + >>> pdb.run("f(2)") + > (1)() + (Pdb) continue + 0.5 + >>> The typical usage to inspect a crashed program is:: >>> import pdb - >>> import mymodule - >>> mymodule.test() + >>> def f(x): + ... print(1 / x) + ... + >>> f(0) Traceback (most recent call last): File "", line 1, in - File "./mymodule.py", line 4, in test - test2() - File "./mymodule.py", line 3, in test2 - print(spam) - NameError: spam + File "", line 2, in f + ZeroDivisionError: division by zero >>> pdb.pm() - > ./mymodule.py(3)test2() - -> print(spam) + > (2)f() + (Pdb) p x + 0 (Pdb) @@ -275,7 +293,7 @@ can be overridden by the local file. .. pdbcommand:: w(here) - Print a stack trace, with the most recent frame at the bottom. An arrow + Print a stack trace, with the most recent frame at the bottom. An arrow (``>``) indicates the current frame, which determines the context of most commands. .. pdbcommand:: d(own) [count] @@ -442,7 +460,7 @@ can be overridden by the local file. .. pdbcommand:: a(rgs) - Print the argument list of the current function. + Print the arguments of the current function and their current values. .. pdbcommand:: p expression @@ -476,6 +494,50 @@ can be overridden by the local file. Without *expression*, list all display expressions for the current frame. + .. note:: + + Display evaluates *expression* and compares to the result of the previous + evaluation of *expression*, so when the result is mutable, display may not + be able to pick up the changes. + + Example:: + + lst = [] + breakpoint() + pass + lst.append(1) + print(lst) + + Display won't realize ``lst`` has been changed because the result of evaluation + is modified in place by ``lst.append(1)`` before being compared:: + + > example.py(3)() + -> pass + (Pdb) display lst + display lst: [] + (Pdb) n + > example.py(4)() + -> lst.append(1) + (Pdb) n + > example.py(5)() + -> print(lst) + (Pdb) + + You can do some tricks with copy mechanism to make it work:: + + > example.py(3)() + -> pass + (Pdb) display lst[:] + display lst[:]: [] + (Pdb) n + > example.py(4)() + -> lst.append(1) + (Pdb) n + > example.py(5)() + -> print(lst) + display lst[:]: [1] [old: []] + (Pdb) + .. versionadded:: 3.2 .. pdbcommand:: undisplay [expression] @@ -552,7 +614,7 @@ can be overridden by the local file. .. pdbcommand:: retval - Print the return value for the last return of a function. + Print the return value for the last return of the current function. .. rubric:: Footnotes From webhook-mailer at python.org Wed Apr 12 02:26:41 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 12 Apr 2023 06:26:41 -0000 Subject: [Python-checkins] gh-103237: Polish pdb docs (GH-103238) Message-ID: https://github.com/python/cpython/commit/b5fe28daceeaa3f3e1dfe66b834733cf52a41354 commit: b5fe28daceeaa3f3e1dfe66b834733cf52a41354 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-11T23:26:33-07:00 summary: gh-103237: Polish pdb docs (GH-103238) (cherry picked from commit 449bf2a76b23b97a38158d506bc30d3ebe006321) Co-authored-by: Tian Gao files: M Doc/library/pdb.rst diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index d80c5eebbf27..a556fcc30877 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -36,73 +36,91 @@ extension interface uses the modules :mod:`bdb` and :mod:`cmd`. Module :mod:`traceback` Standard interface to extract, format and print stack traces of Python programs. -The debugger's prompt is ``(Pdb)``. Typical usage to run a program under control -of the debugger is:: +The typical usage to break into the debugger is to insert:: - >>> import pdb - >>> import mymodule - >>> pdb.run('mymodule.test()') - > (0)?() - (Pdb) continue - > (1)?() + import pdb; pdb.set_trace() + +Or:: + + breakpoint() + +at the location you want to break into the debugger, and then run the program. +You can then step through the code following this statement, and continue +running without the debugger using the :pdbcmd:`continue` command. + +.. versionadded:: 3.7 + The built-in :func:`breakpoint()`, when called with defaults, can be used + instead of ``import pdb; pdb.set_trace()``. + +:: + + def double(x): + breakpoint() + return x * 2 + val = 3 + print(f"{val} * 2 is {double(val)}") + +The debugger's prompt is ``(Pdb)``, which is the indicator that you are in debug mode:: + + > ...(3)double() + -> return x * 2 + (Pdb) p x + 3 (Pdb) continue - NameError: 'spam' - > (1)?() - (Pdb) + 3 * 2 is 6 .. versionchanged:: 3.3 Tab-completion via the :mod:`readline` module is available for commands and command arguments, e.g. the current global and local names are offered as arguments of the ``p`` command. -:file:`pdb.py` can also be invoked as a script to debug other scripts. For + +You can also invoke :mod:`pdb` from the command line to debug other scripts. For example:: python -m pdb myscript.py -When invoked as a script, pdb will automatically enter post-mortem debugging if +When invoked as a module, pdb will automatically enter post-mortem debugging if the program being debugged exits abnormally. After post-mortem debugging (or after normal exit of the program), pdb will restart the program. Automatic restarting preserves pdb's state (such as breakpoints) and in most cases is more useful than quitting the debugger upon program's exit. .. versionadded:: 3.2 - :file:`pdb.py` now accepts a ``-c`` option that executes commands as if given + ``-c`` option is introduced to execute commands as if given in a :file:`.pdbrc` file, see :ref:`debugger-commands`. .. versionadded:: 3.7 - :file:`pdb.py` now accepts a ``-m`` option that execute modules similar to the way + ``-m`` option is introduced to execute modules similar to the way ``python -m`` does. As with a script, the debugger will pause execution just before the first line of the module. +Typical usage to execute a statement under control of the debugger is:: -The typical usage to break into the debugger is to insert:: - - import pdb; pdb.set_trace() - -at the location you want to break into the debugger, and then run the program. -You can then step through the code following this statement, and continue -running without the debugger using the :pdbcmd:`continue` command. - -.. versionadded:: 3.7 - The built-in :func:`breakpoint()`, when called with defaults, can be used - instead of ``import pdb; pdb.set_trace()``. + >>> import pdb + >>> def f(x): + ... print(1 / x) + >>> pdb.run("f(2)") + > (1)() + (Pdb) continue + 0.5 + >>> The typical usage to inspect a crashed program is:: >>> import pdb - >>> import mymodule - >>> mymodule.test() + >>> def f(x): + ... print(1 / x) + ... + >>> f(0) Traceback (most recent call last): File "", line 1, in - File "./mymodule.py", line 4, in test - test2() - File "./mymodule.py", line 3, in test2 - print(spam) - NameError: spam + File "", line 2, in f + ZeroDivisionError: division by zero >>> pdb.pm() - > ./mymodule.py(3)test2() - -> print(spam) + > (2)f() + (Pdb) p x + 0 (Pdb) @@ -275,7 +293,7 @@ can be overridden by the local file. .. pdbcommand:: w(here) - Print a stack trace, with the most recent frame at the bottom. An arrow + Print a stack trace, with the most recent frame at the bottom. An arrow (``>``) indicates the current frame, which determines the context of most commands. .. pdbcommand:: d(own) [count] @@ -442,7 +460,7 @@ can be overridden by the local file. .. pdbcommand:: a(rgs) - Print the argument list of the current function. + Print the arguments of the current function and their current values. .. pdbcommand:: p expression @@ -476,6 +494,50 @@ can be overridden by the local file. Without *expression*, list all display expressions for the current frame. + .. note:: + + Display evaluates *expression* and compares to the result of the previous + evaluation of *expression*, so when the result is mutable, display may not + be able to pick up the changes. + + Example:: + + lst = [] + breakpoint() + pass + lst.append(1) + print(lst) + + Display won't realize ``lst`` has been changed because the result of evaluation + is modified in place by ``lst.append(1)`` before being compared:: + + > example.py(3)() + -> pass + (Pdb) display lst + display lst: [] + (Pdb) n + > example.py(4)() + -> lst.append(1) + (Pdb) n + > example.py(5)() + -> print(lst) + (Pdb) + + You can do some tricks with copy mechanism to make it work:: + + > example.py(3)() + -> pass + (Pdb) display lst[:] + display lst[:]: [] + (Pdb) n + > example.py(4)() + -> lst.append(1) + (Pdb) n + > example.py(5)() + -> print(lst) + display lst[:]: [1] [old: []] + (Pdb) + .. versionadded:: 3.2 .. pdbcommand:: undisplay [expression] @@ -552,7 +614,7 @@ can be overridden by the local file. .. pdbcommand:: retval - Print the return value for the last return of a function. + Print the return value for the last return of the current function. .. rubric:: Footnotes From webhook-mailer at python.org Wed Apr 12 03:36:13 2023 From: webhook-mailer at python.org (vsajip) Date: Wed, 12 Apr 2023 07:36:13 -0000 Subject: [Python-checkins] gh-103357: Add logging.Formatter defaults support to logging.config fileConfig and dictConfig (GH-103359) Message-ID: https://github.com/python/cpython/commit/8f54302ab49a07e857843f1a551db5ddb536ce56 commit: 8f54302ab49a07e857843f1a551db5ddb536ce56 branch: main author: Bar Harel committer: vsajip date: 2023-04-12T08:35:56+01:00 summary: gh-103357: Add logging.Formatter defaults support to logging.config fileConfig and dictConfig (GH-103359) files: A Misc/NEWS.d/next/Library/2023-04-08-01-33-12.gh-issue-103357.vjin28.rst M Doc/library/logging.config.rst M Lib/logging/config.py M Lib/test/test_logging.py diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst index 2daf2422ebd5..250246b5cd9a 100644 --- a/Doc/library/logging.config.rst +++ b/Doc/library/logging.config.rst @@ -253,6 +253,7 @@ otherwise, the context is used to determine what to instantiate. * ``datefmt`` * ``style`` * ``validate`` (since version >=3.8) + * ``defaults`` (since version >=3.12) An optional ``class`` key indicates the name of the formatter's class (as a dotted module and class name). The instantiation @@ -953,16 +954,22 @@ Sections which specify formatter configuration are typified by the following. .. code-block:: ini [formatter_form01] - format=F1 %(asctime)s %(levelname)s %(message)s + format=F1 %(asctime)s %(levelname)s %(message)s %(customfield)s datefmt= style=% validate=True + defaults={'customfield': 'defaultvalue'} class=logging.Formatter The arguments for the formatter configuration are the same as the keys in the dictionary schema :ref:`formatters section `. +The ``defaults`` entry, when :ref:`evaluated ` in the context of +the ``logging`` package's namespace, is a dictionary of default values for +custom formatting fields. If not provided, it defaults to ``None``. + + .. note:: Due to the use of :func:`eval` as described above, there are diff --git a/Lib/logging/config.py b/Lib/logging/config.py index 7cd16c643e9d..16c54a6a4f7a 100644 --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -114,11 +114,18 @@ def _create_formatters(cp): fs = cp.get(sectname, "format", raw=True, fallback=None) dfs = cp.get(sectname, "datefmt", raw=True, fallback=None) stl = cp.get(sectname, "style", raw=True, fallback='%') + defaults = cp.get(sectname, "defaults", raw=True, fallback=None) + c = logging.Formatter class_name = cp[sectname].get("class") if class_name: c = _resolve(class_name) - f = c(fs, dfs, stl) + + if defaults is not None: + defaults = eval(defaults, vars(logging)) + f = c(fs, dfs, stl, defaults=defaults) + else: + f = c(fs, dfs, stl) formatters[form] = f return formatters @@ -668,18 +675,27 @@ def configure_formatter(self, config): dfmt = config.get('datefmt', None) style = config.get('style', '%') cname = config.get('class', None) + defaults = config.get('defaults', None) if not cname: c = logging.Formatter else: c = _resolve(cname) + kwargs = {} + + # Add defaults only if it exists. + # Prevents TypeError in custom formatter callables that do not + # accept it. + if defaults is not None: + kwargs['defaults'] = defaults + # A TypeError would be raised if "validate" key is passed in with a formatter callable # that does not accept "validate" as a parameter if 'validate' in config: # if user hasn't mentioned it, the default will be fine - result = c(fmt, dfmt, style, config['validate']) + result = c(fmt, dfmt, style, config['validate'], **kwargs) else: - result = c(fmt, dfmt, style) + result = c(fmt, dfmt, style, **kwargs) return result diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index c6de34e9dbdc..9176d8eeb56d 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -1524,6 +1524,32 @@ class ConfigFileTest(BaseTest): kwargs={{"encoding": "utf-8"}} """ + + config9 = """ + [loggers] + keys=root + + [handlers] + keys=hand1 + + [formatters] + keys=form1 + + [logger_root] + level=WARNING + handlers=hand1 + + [handler_hand1] + class=StreamHandler + level=NOTSET + formatter=form1 + args=(sys.stdout,) + + [formatter_form1] + format=%(message)s ++ %(customfield)s + defaults={"customfield": "defaultvalue"} + """ + disable_test = """ [loggers] keys=root @@ -1687,6 +1713,16 @@ def test_config8_ok(self): handler = logging.root.handlers[0] self.addCleanup(closeFileHandler, handler, fn) + def test_config9_ok(self): + self.apply_config(self.config9) + formatter = logging.root.handlers[0].formatter + result = formatter.format(logging.makeLogRecord({'msg': 'test'})) + self.assertEqual(result, 'test ++ defaultvalue') + result = formatter.format(logging.makeLogRecord( + {'msg': 'test', 'customfield': "customvalue"})) + self.assertEqual(result, 'test ++ customvalue') + + def test_logger_disabling(self): self.apply_config(self.disable_test) logger = logging.getLogger('some_pristine_logger') @@ -2909,6 +2945,30 @@ class ConfigDictTest(BaseTest): }, } + # config0 but with default values for formatter. Skipped 15, it is defined + # in the test code. + config16 = { + 'version': 1, + 'formatters': { + 'form1' : { + 'format' : '%(message)s ++ %(customfield)s', + 'defaults': {"customfield": "defaultvalue"} + }, + }, + 'handlers' : { + 'hand1' : { + 'class' : 'logging.StreamHandler', + 'formatter' : 'form1', + 'level' : 'NOTSET', + 'stream' : 'ext://sys.stdout', + }, + }, + 'root' : { + 'level' : 'WARNING', + 'handlers' : ['hand1'], + }, + } + bad_format = { "version": 1, "formatters": { @@ -3021,7 +3081,7 @@ class ConfigDictTest(BaseTest): } } - # Configuration with custom function and 'validate' set to False + # Configuration with custom function, 'validate' set to False and no defaults custom_formatter_with_function = { 'version': 1, 'formatters': { @@ -3048,6 +3108,33 @@ class ConfigDictTest(BaseTest): } } + # Configuration with custom function, and defaults + custom_formatter_with_defaults = { + 'version': 1, + 'formatters': { + 'form1': { + '()': formatFunc, + 'format': '%(levelname)s:%(name)s:%(message)s:%(customfield)s', + 'defaults': {"customfield": "myvalue"} + }, + }, + 'handlers' : { + 'hand1' : { + 'class': 'logging.StreamHandler', + 'formatter': 'form1', + 'level': 'NOTSET', + 'stream': 'ext://sys.stdout', + }, + }, + "loggers": { + "my_test_logger_custom_formatter": { + "level": "DEBUG", + "handlers": ["hand1"], + "propagate": "true" + } + } + } + config_queue_handler = { 'version': 1, 'handlers' : { @@ -3349,6 +3436,22 @@ def test_config15_ok(self): handler = logging.root.handlers[0] self.addCleanup(closeFileHandler, handler, fn) + def test_config16_ok(self): + self.apply_config(self.config16) + h = logging._handlers['hand1'] + + # Custom value + result = h.formatter.format(logging.makeLogRecord( + {'msg': 'Hello', 'customfield': 'customvalue'})) + self.assertEqual(result, 'Hello ++ customvalue') + + # Default value + result = h.formatter.format(logging.makeLogRecord( + {'msg': 'Hello'})) + self.assertEqual(result, 'Hello ++ defaultvalue') + + + def setup_via_listener(self, text, verify=None): text = text.encode("utf-8") # Ask for a randomly assigned port (by using port 0) @@ -3516,6 +3619,9 @@ def test_custom_formatter_class_with_validate3(self): def test_custom_formatter_function_with_validate(self): self.assertRaises(ValueError, self.apply_config, self.custom_formatter_with_function) + def test_custom_formatter_function_with_defaults(self): + self.assertRaises(ValueError, self.apply_config, self.custom_formatter_with_defaults) + def test_baseconfig(self): d = { 'atuple': (1, 2, 3), diff --git a/Misc/NEWS.d/next/Library/2023-04-08-01-33-12.gh-issue-103357.vjin28.rst b/Misc/NEWS.d/next/Library/2023-04-08-01-33-12.gh-issue-103357.vjin28.rst new file mode 100644 index 000000000000..83dce56ed0b7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-08-01-33-12.gh-issue-103357.vjin28.rst @@ -0,0 +1,3 @@ +Added support for :class:`logging.Formatter` ``defaults`` parameter to +:func:`logging.config.dictConfig` and :func:`logging.config.fileConfig`. +Patch by Bar Harel. From webhook-mailer at python.org Wed Apr 12 04:44:43 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 12 Apr 2023 08:44:43 -0000 Subject: [Python-checkins] GH-83893: Cross reference env. vars and -X command line options (GH-103414) Message-ID: https://github.com/python/cpython/commit/d65ed693a8a13a2a7f9b201bda1224d6ae5fcf0e commit: d65ed693a8a13a2a7f9b201bda1224d6ae5fcf0e branch: main author: Furkan Onder committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-12T01:44:35-07:00 summary: GH-83893: Cross reference env. vars and -X command line options (GH-103414) Co-authored-by: Erlend E. Aasland files: M Doc/using/cmdline.rst diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 2a4d070ec057..b35e8454fa2a 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -495,7 +495,8 @@ Miscellaneous options Reserved for various implementation-specific options. CPython currently defines the following possible values: - * ``-X faulthandler`` to enable :mod:`faulthandler`; + * ``-X faulthandler`` to enable :mod:`faulthandler`. + See also :envvar:`PYTHONFAULTHANDLER`. * ``-X showrefcount`` to output the total reference count and number of used memory blocks when the program finishes or after each statement in the interactive interpreter. This only works on :ref:`debug builds @@ -503,8 +504,9 @@ Miscellaneous options * ``-X tracemalloc`` to start tracing Python memory allocations using the :mod:`tracemalloc` module. By default, only the most recent frame is stored in a traceback of a trace. Use ``-X tracemalloc=NFRAME`` to start - tracing with a traceback limit of *NFRAME* frames. See the - :func:`tracemalloc.start` for more information. + tracing with a traceback limit of *NFRAME* frames. + See :func:`tracemalloc.start` and :envvar:`PYTHONTRACEMALLOC` + for more information. * ``-X int_max_str_digits`` configures the :ref:`integer string conversion length limitation `. See also :envvar:`PYTHONINTMAXSTRDIGITS`. @@ -519,6 +521,7 @@ Miscellaneous options * ``-X utf8`` enables the :ref:`Python UTF-8 Mode `. ``-X utf8=0`` explicitly disables :ref:`Python UTF-8 Mode ` (even when it would otherwise activate automatically). + See also :envvar:`PYTHONUTF8`. * ``-X pycache_prefix=PATH`` enables writing ``.pyc`` files to a parallel tree rooted at the given directory instead of to the code tree. See also :envvar:`PYTHONPYCACHEPREFIX`. @@ -861,7 +864,9 @@ conflict. Python memory allocations using the :mod:`tracemalloc` module. The value of the variable is the maximum number of frames stored in a traceback of a trace. For example, ``PYTHONTRACEMALLOC=1`` stores only the most recent - frame. See the :func:`tracemalloc.start` for more information. + frame. + See the :func:`tracemalloc.start` function for more information. + This is equivalent to setting the :option:`-X` ``tracemalloc`` option. .. versionadded:: 3.4 @@ -869,8 +874,8 @@ conflict. .. envvar:: PYTHONPROFILEIMPORTTIME If this environment variable is set to a non-empty string, Python will - show how long each import takes. This is exactly equivalent to setting - ``-X importtime`` on the command line. + show how long each import takes. + This is equivalent to setting the :option:`-X` ``importtime`` option. .. versionadded:: 3.7 @@ -1012,6 +1017,7 @@ conflict. If this environment variable is set to a non-empty string, enable :ref:`Python Development Mode `, introducing additional runtime checks that are too expensive to be enabled by default. + This is equivalent to setting the :option:`-X` ``dev`` option. .. versionadded:: 3.7 From webhook-mailer at python.org Wed Apr 12 04:59:29 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Wed, 12 Apr 2023 08:59:29 -0000 Subject: [Python-checkins] gh-103417: use time.monotonic in the example for sched.scheduler (#103418) Message-ID: https://github.com/python/cpython/commit/f2b7ecb7783299c4555e89125ca9ba8e89854643 commit: f2b7ecb7783299c4555e89125ca9ba8e89854643 branch: main author: Nick Burns committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-04-12T01:59:21-07:00 summary: gh-103417: use time.monotonic in the example for sched.scheduler (#103418) files: M Doc/library/sched.rst diff --git a/Doc/library/sched.rst b/Doc/library/sched.rst index a051c65b97b0..04215d31ba10 100644 --- a/Doc/library/sched.rst +++ b/Doc/library/sched.rst @@ -36,7 +36,7 @@ scheduler: Example:: >>> import sched, time - >>> s = sched.scheduler(time.time, time.sleep) + >>> s = sched.scheduler(time.monotonic, time.sleep) >>> def print_time(a='default'): ... print("From print_time", time.time(), a) ... From webhook-mailer at python.org Wed Apr 12 05:09:25 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 12 Apr 2023 09:09:25 -0000 Subject: [Python-checkins] gh-103417: use time.monotonic in the example for sched.scheduler (GH-103418) Message-ID: https://github.com/python/cpython/commit/e643412ef443b7a6847833f1e140b567622ac383 commit: e643412ef443b7a6847833f1e140b567622ac383 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-12T02:09:08-07:00 summary: gh-103417: use time.monotonic in the example for sched.scheduler (GH-103418) (cherry picked from commit f2b7ecb7783299c4555e89125ca9ba8e89854643) Co-authored-by: Nick Burns files: M Doc/library/sched.rst diff --git a/Doc/library/sched.rst b/Doc/library/sched.rst index a051c65b97b0..04215d31ba10 100644 --- a/Doc/library/sched.rst +++ b/Doc/library/sched.rst @@ -36,7 +36,7 @@ scheduler: Example:: >>> import sched, time - >>> s = sched.scheduler(time.time, time.sleep) + >>> s = sched.scheduler(time.monotonic, time.sleep) >>> def print_time(a='default'): ... print("From print_time", time.time(), a) ... From webhook-mailer at python.org Wed Apr 12 06:41:58 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Wed, 12 Apr 2023 10:41:58 -0000 Subject: [Python-checkins] gh-103092: Isolate msvcrt (#103248) Message-ID: https://github.com/python/cpython/commit/dce2d38cb04b541bad477ccc1040a68fa70a9a69 commit: dce2d38cb04b541bad477ccc1040a68fa70a9a69 branch: main author: AN Long committer: erlend-aasland date: 2023-04-12T12:41:21+02:00 summary: gh-103092: Isolate msvcrt (#103248) files: A Misc/NEWS.d/next/Library/2023-04-04-21-44-25.gh-issue-103092.Dz0_Xn.rst M PC/msvcrtmodule.c diff --git a/Misc/NEWS.d/next/Library/2023-04-04-21-44-25.gh-issue-103092.Dz0_Xn.rst b/Misc/NEWS.d/next/Library/2023-04-04-21-44-25.gh-issue-103092.Dz0_Xn.rst new file mode 100644 index 000000000000..7bd191e3c22b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-04-21-44-25.gh-issue-103092.Dz0_Xn.rst @@ -0,0 +1 @@ +Adapt the :mod:`msvcrt` extension module to :pep:`687`. diff --git a/PC/msvcrtmodule.c b/PC/msvcrtmodule.c index 6e8b423c3839..de9a88946aff 100644 --- a/PC/msvcrtmodule.c +++ b/PC/msvcrtmodule.c @@ -564,19 +564,6 @@ static struct PyMethodDef msvcrt_functions[] = { {NULL, NULL} }; - -static struct PyModuleDef msvcrtmodule = { - PyModuleDef_HEAD_INIT, - "msvcrt", - NULL, - -1, - msvcrt_functions, - NULL, - NULL, - NULL, - NULL -}; - static void insertint(PyObject *d, char *name, int value) { @@ -605,14 +592,10 @@ insertptr(PyObject *d, char *name, void *value) } } -PyMODINIT_FUNC -PyInit_msvcrt(void) +static int +exec_module(PyObject* m) { int st; - PyObject *m = PyModule_Create(&msvcrtmodule); - if (m == NULL) { - return NULL; - } PyObject *d = PyModule_GetDict(m); // Borrowed ref. /* constants for the locking() function's mode argument */ @@ -645,21 +628,21 @@ PyInit_msvcrt(void) st = PyModule_AddStringConstant(m, "VC_ASSEMBLY_PUBLICKEYTOKEN", _VC_ASSEMBLY_PUBLICKEYTOKEN); if (st < 0) { - goto error; + return -1; } #endif #ifdef _CRT_ASSEMBLY_VERSION st = PyModule_AddStringConstant(m, "CRT_ASSEMBLY_VERSION", _CRT_ASSEMBLY_VERSION); if (st < 0) { - goto error; + return -1; } #endif #ifdef __LIBRARIES_ASSEMBLY_NAME_PREFIX st = PyModule_AddStringConstant(m, "LIBRARIES_ASSEMBLY_NAME_PREFIX", __LIBRARIES_ASSEMBLY_NAME_PREFIX); if (st < 0) { - goto error; + return -1; } #endif @@ -671,20 +654,34 @@ PyInit_msvcrt(void) _VC_CRT_BUILD_VERSION, _VC_CRT_RBUILD_VERSION); if (version == NULL) { - goto error; + return -1; } st = PyModule_AddObjectRef(m, "CRT_ASSEMBLY_VERSION", version); Py_DECREF(version); if (st < 0) { - goto error; + return -1; } #endif /* make compiler warning quiet if st is unused */ (void)st; - return m; + return 0; +} + +static PyModuleDef_Slot msvcrt_slots[] = { + {Py_mod_exec, exec_module}, + {0, NULL} +}; -error: - Py_DECREF(m); - return NULL; +static struct PyModuleDef msvcrtmodule = { + .m_base = PyModuleDef_HEAD_INIT, + .m_name = "msvcrt", + .m_methods = msvcrt_functions, + .m_slots = msvcrt_slots, +}; + +PyMODINIT_FUNC +PyInit_msvcrt(void) +{ + return PyModuleDef_Init(&msvcrtmodule); } From webhook-mailer at python.org Wed Apr 12 07:05:05 2023 From: webhook-mailer at python.org (markshannon) Date: Wed, 12 Apr 2023 11:05:05 -0000 Subject: [Python-checkins] GH-103082: Implementation of PEP 669: Low Impact Monitoring for CPython (GH-103083) Message-ID: https://github.com/python/cpython/commit/411b1692811b2ecac59cb0df0f920861c7cf179a commit: 411b1692811b2ecac59cb0df0f920861c7cf179a branch: main author: Mark Shannon committer: markshannon date: 2023-04-12T12:04:55+01:00 summary: GH-103082: Implementation of PEP 669: Low Impact Monitoring for CPython (GH-103083) * The majority of the monitoring code is in instrumentation.c * The new instrumentation bytecodes are in bytecodes.c * legacy_tracing.c adapts the new API to the old sys.setrace and sys.setprofile APIs files: A Include/internal/pycore_instruments.h A Lib/test/test_monitoring.py A Misc/NEWS.d/next/Core and Builtins/2023-03-31-17-24-03.gh-issue-103082.isRUcV.rst A Python/clinic/instrumentation.c.h A Python/instrumentation.c A Python/legacy_tracing.c M Include/cpython/code.h M Include/cpython/pystate.h M Include/internal/pycore_code.h M Include/internal/pycore_frame.h M Include/internal/pycore_interp.h M Include/internal/pycore_opcode.h M Include/internal/pycore_pystate.h M Include/opcode.h M Lib/importlib/_bootstrap_external.py M Lib/opcode.py M Lib/test/test__opcode.py M Lib/test/test_bdb.py M Lib/test/test_code.py M Lib/test/test_dis.py M Lib/test/test_sys.py M Lib/test/test_sys_settrace.py M Makefile.pre.in M Objects/codeobject.c M Objects/frameobject.c M Objects/object.c M PCbuild/_freeze_module.vcxproj M PCbuild/_freeze_module.vcxproj.filters M PCbuild/pythoncore.vcxproj M PCbuild/pythoncore.vcxproj.filters M Python/bytecodes.c M Python/ceval.c M Python/ceval_macros.h M Python/compile.c M Python/generated_cases.c.h M Python/makeopcodetargets.py M Python/opcode_metadata.h M Python/opcode_targets.h M Python/pystate.c M Python/specialize.c M Python/sysmodule.c M Tools/build/deepfreeze.py M Tools/build/generate_opcode_h.py M Tools/c-analyzer/cpython/globals-to-fix.tsv diff --git a/Include/cpython/code.h b/Include/cpython/code.h index abcf1250603d..6bead361c792 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -3,10 +3,22 @@ #ifndef Py_LIMITED_API #ifndef Py_CODE_H #define Py_CODE_H + #ifdef __cplusplus extern "C" { #endif + +/* Count of all "real" monitoring events (not derived from other events) */ +#define PY_MONITORING_UNGROUPED_EVENTS 14 +/* Count of all monitoring events */ +#define PY_MONITORING_EVENTS 16 + +/* Table of which tools are active for each monitored event. */ +typedef struct _Py_Monitors { + uint8_t tools[PY_MONITORING_UNGROUPED_EVENTS]; +} _Py_Monitors; + /* Each instruction in a code object is a fixed-width value, * currently 2 bytes: 1-byte opcode + 1-byte oparg. The EXTENDED_ARG * opcode allows for larger values but the current limit is 3 uses @@ -56,6 +68,35 @@ typedef struct { PyObject *_co_freevars; } _PyCoCached; +/* Ancilliary data structure used for instrumentation. + Line instrumentation creates an array of + these. One entry per code unit.*/ +typedef struct { + uint8_t original_opcode; + int8_t line_delta; +} _PyCoLineInstrumentationData; + +/* Main data structure used for instrumentation. + * This is allocated when needed for instrumentation + */ +typedef struct { + /* Monitoring specific to this code object */ + _Py_Monitors local_monitors; + /* Monitoring that is active on this code object */ + _Py_Monitors active_monitors; + /* The tools that are to be notified for events for the matching code unit */ + uint8_t *tools; + /* Information to support line events */ + _PyCoLineInstrumentationData *lines; + /* The tools that are to be notified for line events for the matching code unit */ + uint8_t *line_tools; + /* Information to support instruction events */ + /* The underlying instructions, which can themselves be instrumented */ + uint8_t *per_instruction_opcodes; + /* The tools that are to be notified for instruction events for the matching code unit */ + uint8_t *per_instruction_tools; +} _PyCoMonitoringData; + // To avoid repeating ourselves in deepfreeze.py, all PyCodeObject members are // defined in this macro: #define _PyCode_DEF(SIZE) { \ @@ -87,7 +128,6 @@ typedef struct { PyObject *co_exceptiontable; /* Byte string encoding exception handling \ table */ \ int co_flags; /* CO_..., see below */ \ - short _co_linearray_entry_size; /* Size of each entry in _co_linearray */ \ \ /* The rest are not so impactful on performance. */ \ int co_argcount; /* #arguments, except *args */ \ @@ -114,8 +154,9 @@ typedef struct { PyObject *co_linetable; /* bytes object that holds location info */ \ PyObject *co_weakreflist; /* to support weakrefs to code objects */ \ _PyCoCached *_co_cached; /* cached co_* attributes */ \ + uint64_t _co_instrumentation_version; /* current instrumentation version */ \ + _PyCoMonitoringData *_co_monitoring; /* Monitoring data */ \ int _co_firsttraceable; /* index of first traceable instruction */ \ - char *_co_linearray; /* array of line offsets */ \ /* Scratch space for extra data relating to the code object. \ Type is a void* to keep the format private in codeobject.c to force \ people to go through the proper APIs. */ \ diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index 3efb241e8237..ea6ed8d2bc4a 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -58,12 +58,6 @@ typedef int (*Py_tracefunc)(PyObject *, PyFrameObject *, int, PyObject *); #define PyTrace_C_RETURN 6 #define PyTrace_OPCODE 7 - -typedef struct { - PyCodeObject *code; // The code object for the bounds. May be NULL. - PyCodeAddressRange bounds; // Only valid if code != NULL. -} PyTraceInfo; - // Internal structure: you should not use it directly, but use public functions // like PyThreadState_EnterTracing() and PyThreadState_LeaveTracing(). typedef struct _PyCFrame { @@ -77,7 +71,6 @@ typedef struct _PyCFrame { * discipline and make sure that instances of this struct cannot * accessed outside of their lifetime. */ - uint8_t use_tracing; // 0 or 255 (or'ed into opcode, hence 8-bit type) /* Pointer to the currently executing frame (it can be NULL) */ struct _PyInterpreterFrame *current_frame; struct _PyCFrame *previous; @@ -157,7 +150,7 @@ struct _ts { This is to prevent the actual trace/profile code from being recorded in the trace/profile. */ int tracing; - int tracing_what; /* The event currently being traced, if any. */ + int what_event; /* The event currently being monitored, if any. */ /* Pointer to current _PyCFrame in the C stack frame of the currently, * or most recently, executing _PyEval_EvalFrameDefault. */ @@ -228,8 +221,6 @@ struct _ts { /* Unique thread state id. */ uint64_t id; - PyTraceInfo trace_info; - _PyStackChunk *datastack_chunk; PyObject **datastack_top; PyObject **datastack_limit; diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index faf1be585e17..d32f37ac44d8 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -441,32 +441,6 @@ adaptive_counter_backoff(uint16_t counter) { /* Line array cache for tracing */ -extern int _PyCode_CreateLineArray(PyCodeObject *co); - -static inline int -_PyCode_InitLineArray(PyCodeObject *co) -{ - if (co->_co_linearray) { - return 0; - } - return _PyCode_CreateLineArray(co); -} - -static inline int -_PyCode_LineNumberFromArray(PyCodeObject *co, int index) -{ - assert(co->_co_linearray != NULL); - assert(index >= 0); - assert(index < Py_SIZE(co)); - if (co->_co_linearray_entry_size == 2) { - return ((int16_t *)co->_co_linearray)[index]; - } - else { - assert(co->_co_linearray_entry_size == 4); - return ((int32_t *)co->_co_linearray)[index]; - } -} - typedef struct _PyShimCodeDef { const uint8_t *code; int codelen; @@ -500,6 +474,10 @@ extern uint32_t _Py_next_func_version; #define COMPARISON_NOT_EQUALS (COMPARISON_UNORDERED | COMPARISON_LESS_THAN | COMPARISON_GREATER_THAN) +extern int _Py_Instrument(PyCodeObject *co, PyInterpreterState *interp); + +extern int _Py_GetBaseOpcode(PyCodeObject *code, int offset); + #ifdef __cplusplus } diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 5806cf05f174..856297aaea8a 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -19,6 +19,7 @@ struct _frame { struct _PyInterpreterFrame *f_frame; /* points to the frame data */ PyObject *f_trace; /* Trace function */ int f_lineno; /* Current line number. Only valid if non-zero */ + int f_last_traced_line; /* The last line traced for this frame */ char f_trace_lines; /* Emit per-line trace events? */ char f_trace_opcodes; /* Emit per-opcode trace events? */ char f_fast_as_locals; /* Have the fast locals of this frame been converted to a dict? */ @@ -137,10 +138,16 @@ _PyFrame_GetLocalsArray(_PyInterpreterFrame *frame) return frame->localsplus; } +/* Fetches the stack pointer, and sets stacktop to -1. + Having stacktop <= 0 ensures that invalid + values are not visible to the cycle GC. + We choose -1 rather than 0 to assist debugging. */ static inline PyObject** _PyFrame_GetStackPointer(_PyInterpreterFrame *frame) { - return frame->localsplus+frame->stacktop; + PyObject **sp = frame->localsplus + frame->stacktop; + frame->stacktop = -1; + return sp; } static inline void diff --git a/Include/internal/pycore_instruments.h b/Include/internal/pycore_instruments.h new file mode 100644 index 000000000000..e94d8755546e --- /dev/null +++ b/Include/internal/pycore_instruments.h @@ -0,0 +1,107 @@ + +#ifndef Py_INTERNAL_INSTRUMENT_H +#define Py_INTERNAL_INSTRUMENT_H + + +#include "pycore_bitutils.h" // _Py_popcount32 +#include "pycore_frame.h" + +#include "cpython/code.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PY_MONITORING_TOOL_IDS 8 + +/* Local events. + * These require bytecode instrumentation */ + +#define PY_MONITORING_EVENT_PY_START 0 +#define PY_MONITORING_EVENT_PY_RESUME 1 +#define PY_MONITORING_EVENT_PY_RETURN 2 +#define PY_MONITORING_EVENT_PY_YIELD 3 +#define PY_MONITORING_EVENT_CALL 4 +#define PY_MONITORING_EVENT_LINE 5 +#define PY_MONITORING_EVENT_INSTRUCTION 6 +#define PY_MONITORING_EVENT_JUMP 7 +#define PY_MONITORING_EVENT_BRANCH 8 +#define PY_MONITORING_EVENT_STOP_ITERATION 9 + +#define PY_MONITORING_INSTRUMENTED_EVENTS 10 + +/* Other events, mainly exceptions */ + +#define PY_MONITORING_EVENT_RAISE 10 +#define PY_MONITORING_EVENT_EXCEPTION_HANDLED 11 +#define PY_MONITORING_EVENT_PY_UNWIND 12 +#define PY_MONITORING_EVENT_PY_THROW 13 + + +/* Ancilliary events */ + +#define PY_MONITORING_EVENT_C_RETURN 14 +#define PY_MONITORING_EVENT_C_RAISE 15 + + +typedef uint32_t _PyMonitoringEventSet; + +/* Tool IDs */ + +/* These are defined in PEP 669 for convenience to avoid clashes */ +#define PY_MONITORING_DEBUGGER_ID 0 +#define PY_MONITORING_COVERAGE_ID 1 +#define PY_MONITORING_PROFILER_ID 2 +#define PY_MONITORING_OPTIMIZER_ID 5 + +/* Internal IDs used to suuport sys.setprofile() and sys.settrace() */ +#define PY_MONITORING_SYS_PROFILE_ID 6 +#define PY_MONITORING_SYS_TRACE_ID 7 + + +PyObject *_PyMonitoring_RegisterCallback(int tool_id, int event_id, PyObject *obj); + +int _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events); + +extern int +_Py_call_instrumentation(PyThreadState *tstate, int event, + _PyInterpreterFrame *frame, _Py_CODEUNIT *instr); + +extern int +_Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, + _Py_CODEUNIT *instr); + +extern int +_Py_call_instrumentation_instruction( + PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr); + +int +_Py_call_instrumentation_jump( + PyThreadState *tstate, int event, + _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *target); + +extern int +_Py_call_instrumentation_arg(PyThreadState *tstate, int event, + _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg); + +extern int +_Py_call_instrumentation_2args(PyThreadState *tstate, int event, + _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1); + +extern void +_Py_call_instrumentation_exc0(PyThreadState *tstate, int event, + _PyInterpreterFrame *frame, _Py_CODEUNIT *instr); + +extern void +_Py_call_instrumentation_exc2(PyThreadState *tstate, int event, + _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1); + +extern int +_Py_Instrumentation_GetLine(PyCodeObject *code, int index); + +extern PyObject _PyInstrumentation_MISSING; + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_INSTRUMENT_H */ diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index d64a68cd2da5..86ae3d8dfc18 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -24,6 +24,7 @@ extern "C" { #include "pycore_genobject.h" // struct _Py_async_gen_state #include "pycore_gc.h" // struct _gc_runtime_state #include "pycore_import.h" // struct _import_state +#include "pycore_instruments.h" // PY_MONITORING_EVENTS #include "pycore_list.h" // struct _Py_list_state #include "pycore_global_objects.h" // struct _Py_interp_static_objects #include "pycore_object_state.h" // struct _py_object_state @@ -37,7 +38,6 @@ struct _Py_long_state { int max_str_digits; }; - /* interpreter state */ /* PyInterpreterState holds the global state for one of the runtime's @@ -49,6 +49,9 @@ struct _is { PyInterpreterState *next; + uint64_t monitoring_version; + uint64_t last_restart_version; + struct pythreads { uint64_t next_unique_id; /* The linked list of threads, newest first. */ @@ -148,6 +151,15 @@ struct _is { struct callable_cache callable_cache; PyCodeObject *interpreter_trampoline; + _Py_Monitors monitors; + bool f_opcode_trace_set; + bool sys_profile_initialized; + bool sys_trace_initialized; + Py_ssize_t sys_profiling_threads; /* Count of threads with c_profilefunc set */ + Py_ssize_t sys_tracing_threads; /* Count of threads with c_tracefunc set */ + PyObject *monitoring_callables[PY_MONITORING_TOOL_IDS][PY_MONITORING_EVENTS]; + PyObject *monitoring_tool_names[PY_MONITORING_TOOL_IDS]; + struct _Py_interp_cached_objects cached_objects; struct _Py_interp_static_objects static_objects; diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index f5e9176a3e66..c039d712dc0b 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -112,6 +112,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [DICT_UPDATE] = DICT_UPDATE, [END_ASYNC_FOR] = END_ASYNC_FOR, [END_FOR] = END_FOR, + [END_SEND] = END_SEND, [EXTENDED_ARG] = EXTENDED_ARG, [FORMAT_VALUE] = FORMAT_VALUE, [FOR_ITER] = FOR_ITER, @@ -127,6 +128,23 @@ const uint8_t _PyOpcode_Deopt[256] = { [GET_YIELD_FROM_ITER] = GET_YIELD_FROM_ITER, [IMPORT_FROM] = IMPORT_FROM, [IMPORT_NAME] = IMPORT_NAME, + [INSTRUMENTED_CALL] = INSTRUMENTED_CALL, + [INSTRUMENTED_CALL_FUNCTION_EX] = INSTRUMENTED_CALL_FUNCTION_EX, + [INSTRUMENTED_END_FOR] = INSTRUMENTED_END_FOR, + [INSTRUMENTED_END_SEND] = INSTRUMENTED_END_SEND, + [INSTRUMENTED_FOR_ITER] = INSTRUMENTED_FOR_ITER, + [INSTRUMENTED_INSTRUCTION] = INSTRUMENTED_INSTRUCTION, + [INSTRUMENTED_JUMP_BACKWARD] = INSTRUMENTED_JUMP_BACKWARD, + [INSTRUMENTED_JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD, + [INSTRUMENTED_LINE] = INSTRUMENTED_LINE, + [INSTRUMENTED_POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE, + [INSTRUMENTED_POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE, + [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE, + [INSTRUMENTED_POP_JUMP_IF_TRUE] = INSTRUMENTED_POP_JUMP_IF_TRUE, + [INSTRUMENTED_RESUME] = INSTRUMENTED_RESUME, + [INSTRUMENTED_RETURN_CONST] = INSTRUMENTED_RETURN_CONST, + [INSTRUMENTED_RETURN_VALUE] = INSTRUMENTED_RETURN_VALUE, + [INSTRUMENTED_YIELD_VALUE] = INSTRUMENTED_YIELD_VALUE, [INTERPRETER_EXIT] = INTERPRETER_EXIT, [IS_OP] = IS_OP, [JUMP_BACKWARD] = JUMP_BACKWARD, @@ -179,6 +197,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [PUSH_NULL] = PUSH_NULL, [RAISE_VARARGS] = RAISE_VARARGS, [RERAISE] = RERAISE, + [RESERVED] = RESERVED, [RESUME] = RESUME, [RETURN_CONST] = RETURN_CONST, [RETURN_GENERATOR] = RETURN_GENERATOR, @@ -223,17 +242,19 @@ static const char *const _PyOpcode_OpName[263] = { [PUSH_NULL] = "PUSH_NULL", [INTERPRETER_EXIT] = "INTERPRETER_EXIT", [END_FOR] = "END_FOR", + [END_SEND] = "END_SEND", [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT", [BINARY_OP_ADD_INT] = "BINARY_OP_ADD_INT", [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE", - [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", [NOP] = "NOP", - [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", + [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", [UNARY_NEGATIVE] = "UNARY_NEGATIVE", [UNARY_NOT] = "UNARY_NOT", + [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT", - [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT", [UNARY_INVERT] = "UNARY_INVERT", + [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT", + [RESERVED] = "RESERVED", [BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT", [BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT", [BINARY_SUBSCR_GETITEM] = "BINARY_SUBSCR_GETITEM", @@ -241,21 +262,21 @@ static const char *const _PyOpcode_OpName[263] = { [BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT", [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", - [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", - [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", [BINARY_SUBSCR] = "BINARY_SUBSCR", [BINARY_SLICE] = "BINARY_SLICE", [STORE_SLICE] = "STORE_SLICE", - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", - [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", + [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", + [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", [GET_LEN] = "GET_LEN", [MATCH_MAPPING] = "MATCH_MAPPING", [MATCH_SEQUENCE] = "MATCH_SEQUENCE", [MATCH_KEYS] = "MATCH_KEYS", - [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", [PUSH_EXC_INFO] = "PUSH_EXC_INFO", [CHECK_EXC_MATCH] = "CHECK_EXC_MATCH", [CHECK_EG_MATCH] = "CHECK_EG_MATCH", + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", + [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O", [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE", [CALL_NO_KW_LEN] = "CALL_NO_KW_LEN", @@ -265,8 +286,6 @@ static const char *const _PyOpcode_OpName[263] = { [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", - [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", - [COMPARE_OP_FLOAT] = "COMPARE_OP_FLOAT", [WITH_EXCEPT_START] = "WITH_EXCEPT_START", [GET_AITER] = "GET_AITER", [GET_ANEXT] = "GET_ANEXT", @@ -274,39 +293,39 @@ static const char *const _PyOpcode_OpName[263] = { [BEFORE_WITH] = "BEFORE_WITH", [END_ASYNC_FOR] = "END_ASYNC_FOR", [CLEANUP_THROW] = "CLEANUP_THROW", + [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", + [COMPARE_OP_FLOAT] = "COMPARE_OP_FLOAT", [COMPARE_OP_INT] = "COMPARE_OP_INT", [COMPARE_OP_STR] = "COMPARE_OP_STR", - [FOR_ITER_LIST] = "FOR_ITER_LIST", - [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", [STORE_SUBSCR] = "STORE_SUBSCR", [DELETE_SUBSCR] = "DELETE_SUBSCR", + [FOR_ITER_LIST] = "FOR_ITER_LIST", + [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", [FOR_ITER_RANGE] = "FOR_ITER_RANGE", [FOR_ITER_GEN] = "FOR_ITER_GEN", [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", - [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", - [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", [GET_ITER] = "GET_ITER", [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", - [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", + [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", - [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", - [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", + [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", + [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", [RETURN_GENERATOR] = "RETURN_GENERATOR", + [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", + [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", + [RETURN_VALUE] = "RETURN_VALUE", [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", + [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", - [RETURN_VALUE] = "RETURN_VALUE", [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", - [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", - [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", - [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [POP_EXCEPT] = "POP_EXCEPT", [STORE_NAME] = "STORE_NAME", [DELETE_NAME] = "DELETE_NAME", @@ -329,9 +348,9 @@ static const char *const _PyOpcode_OpName[263] = { [IMPORT_NAME] = "IMPORT_NAME", [IMPORT_FROM] = "IMPORT_FROM", [JUMP_FORWARD] = "JUMP_FORWARD", + [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", + [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", - [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", - [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -359,9 +378,9 @@ static const char *const _PyOpcode_OpName[263] = { [STORE_DEREF] = "STORE_DEREF", [DELETE_DEREF] = "DELETE_DEREF", [JUMP_BACKWARD] = "JUMP_BACKWARD", - [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", + [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", - [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", + [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -371,14 +390,14 @@ static const char *const _PyOpcode_OpName[263] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", - [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", - [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", + [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", + [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", + [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", + [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", [SEND_GEN] = "SEND_GEN", - [159] = "<159>", - [160] = "<160>", [161] = "<161>", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", @@ -456,24 +475,24 @@ static const char *const _PyOpcode_OpName[263] = { [235] = "<235>", [236] = "<236>", [237] = "<237>", - [238] = "<238>", - [239] = "<239>", - [240] = "<240>", - [241] = "<241>", - [242] = "<242>", - [243] = "<243>", - [244] = "<244>", - [245] = "<245>", - [246] = "<246>", - [247] = "<247>", - [248] = "<248>", - [249] = "<249>", - [250] = "<250>", - [251] = "<251>", - [252] = "<252>", - [253] = "<253>", - [254] = "<254>", - [DO_TRACING] = "DO_TRACING", + [INSTRUMENTED_POP_JUMP_IF_NONE] = "INSTRUMENTED_POP_JUMP_IF_NONE", + [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = "INSTRUMENTED_POP_JUMP_IF_NOT_NONE", + [INSTRUMENTED_RESUME] = "INSTRUMENTED_RESUME", + [INSTRUMENTED_CALL] = "INSTRUMENTED_CALL", + [INSTRUMENTED_RETURN_VALUE] = "INSTRUMENTED_RETURN_VALUE", + [INSTRUMENTED_YIELD_VALUE] = "INSTRUMENTED_YIELD_VALUE", + [INSTRUMENTED_CALL_FUNCTION_EX] = "INSTRUMENTED_CALL_FUNCTION_EX", + [INSTRUMENTED_JUMP_FORWARD] = "INSTRUMENTED_JUMP_FORWARD", + [INSTRUMENTED_JUMP_BACKWARD] = "INSTRUMENTED_JUMP_BACKWARD", + [INSTRUMENTED_RETURN_CONST] = "INSTRUMENTED_RETURN_CONST", + [INSTRUMENTED_FOR_ITER] = "INSTRUMENTED_FOR_ITER", + [INSTRUMENTED_POP_JUMP_IF_FALSE] = "INSTRUMENTED_POP_JUMP_IF_FALSE", + [INSTRUMENTED_POP_JUMP_IF_TRUE] = "INSTRUMENTED_POP_JUMP_IF_TRUE", + [INSTRUMENTED_END_FOR] = "INSTRUMENTED_END_FOR", + [INSTRUMENTED_END_SEND] = "INSTRUMENTED_END_SEND", + [INSTRUMENTED_INSTRUCTION] = "INSTRUMENTED_INSTRUCTION", + [INSTRUMENTED_LINE] = "INSTRUMENTED_LINE", + [255] = "<255>", [SETUP_FINALLY] = "SETUP_FINALLY", [SETUP_CLEANUP] = "SETUP_CLEANUP", [SETUP_WITH] = "SETUP_WITH", @@ -485,8 +504,6 @@ static const char *const _PyOpcode_OpName[263] = { #endif #define EXTRA_CASES \ - case 159: \ - case 160: \ case 161: \ case 166: \ case 167: \ @@ -556,23 +573,7 @@ static const char *const _PyOpcode_OpName[263] = { case 235: \ case 236: \ case 237: \ - case 238: \ - case 239: \ - case 240: \ - case 241: \ - case 242: \ - case 243: \ - case 244: \ - case 245: \ - case 246: \ - case 247: \ - case 248: \ - case 249: \ - case 250: \ - case 251: \ - case 252: \ - case 253: \ - case 254: \ + case 255: \ ; #ifdef __cplusplus diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index b5408622d9d4..6e5f2289cb6b 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -133,16 +133,6 @@ extern void _PyThreadState_BindDetached(PyThreadState *); extern void _PyThreadState_UnbindDetached(PyThreadState *); -static inline void -_PyThreadState_UpdateTracingState(PyThreadState *tstate) -{ - bool use_tracing = - (tstate->tracing == 0) && - (tstate->c_tracefunc != NULL || tstate->c_profilefunc != NULL); - tstate->cframe->use_tracing = (use_tracing ? 255 : 0); -} - - /* Other */ PyAPI_FUNC(PyThreadState *) _PyThreadState_Swap( diff --git a/Include/opcode.h b/Include/opcode.h index 0ff84dc5a551..aa8716ef5b40 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -13,10 +13,12 @@ extern "C" { #define PUSH_NULL 2 #define INTERPRETER_EXIT 3 #define END_FOR 4 +#define END_SEND 5 #define NOP 9 #define UNARY_NEGATIVE 11 #define UNARY_NOT 12 #define UNARY_INVERT 15 +#define RESERVED 17 #define BINARY_SUBSCR 25 #define BINARY_SLICE 26 #define STORE_SLICE 27 @@ -114,6 +116,24 @@ extern "C" { #define KW_NAMES 172 #define CALL_INTRINSIC_1 173 #define CALL_INTRINSIC_2 174 +#define MIN_INSTRUMENTED_OPCODE 238 +#define INSTRUMENTED_POP_JUMP_IF_NONE 238 +#define INSTRUMENTED_POP_JUMP_IF_NOT_NONE 239 +#define INSTRUMENTED_RESUME 240 +#define INSTRUMENTED_CALL 241 +#define INSTRUMENTED_RETURN_VALUE 242 +#define INSTRUMENTED_YIELD_VALUE 243 +#define INSTRUMENTED_CALL_FUNCTION_EX 244 +#define INSTRUMENTED_JUMP_FORWARD 245 +#define INSTRUMENTED_JUMP_BACKWARD 246 +#define INSTRUMENTED_RETURN_CONST 247 +#define INSTRUMENTED_FOR_ITER 248 +#define INSTRUMENTED_POP_JUMP_IF_FALSE 249 +#define INSTRUMENTED_POP_JUMP_IF_TRUE 250 +#define INSTRUMENTED_END_FOR 251 +#define INSTRUMENTED_END_SEND 252 +#define INSTRUMENTED_INSTRUCTION 253 +#define INSTRUMENTED_LINE 254 #define MIN_PSEUDO_OPCODE 256 #define SETUP_FINALLY 256 #define SETUP_CLEANUP 257 @@ -123,69 +143,68 @@ extern "C" { #define JUMP_NO_INTERRUPT 261 #define LOAD_METHOD 262 #define MAX_PSEUDO_OPCODE 262 -#define BINARY_OP_ADD_FLOAT 5 -#define BINARY_OP_ADD_INT 6 -#define BINARY_OP_ADD_UNICODE 7 -#define BINARY_OP_INPLACE_ADD_UNICODE 8 -#define BINARY_OP_MULTIPLY_FLOAT 10 -#define BINARY_OP_MULTIPLY_INT 13 -#define BINARY_OP_SUBTRACT_FLOAT 14 -#define BINARY_OP_SUBTRACT_INT 16 -#define BINARY_SUBSCR_DICT 17 -#define BINARY_SUBSCR_GETITEM 18 -#define BINARY_SUBSCR_LIST_INT 19 -#define BINARY_SUBSCR_TUPLE_INT 20 -#define CALL_PY_EXACT_ARGS 21 -#define CALL_PY_WITH_DEFAULTS 22 -#define CALL_BOUND_METHOD_EXACT_ARGS 23 -#define CALL_BUILTIN_CLASS 24 -#define CALL_BUILTIN_FAST_WITH_KEYWORDS 28 -#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 29 -#define CALL_NO_KW_BUILTIN_FAST 34 -#define CALL_NO_KW_BUILTIN_O 38 -#define CALL_NO_KW_ISINSTANCE 39 -#define CALL_NO_KW_LEN 40 -#define CALL_NO_KW_LIST_APPEND 41 -#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 42 -#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 43 -#define CALL_NO_KW_METHOD_DESCRIPTOR_O 44 -#define CALL_NO_KW_STR_1 45 -#define CALL_NO_KW_TUPLE_1 46 -#define CALL_NO_KW_TYPE_1 47 -#define COMPARE_OP_FLOAT 48 -#define COMPARE_OP_INT 56 -#define COMPARE_OP_STR 57 -#define FOR_ITER_LIST 58 -#define FOR_ITER_TUPLE 59 -#define FOR_ITER_RANGE 62 -#define FOR_ITER_GEN 63 -#define LOAD_ATTR_CLASS 64 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 65 -#define LOAD_ATTR_INSTANCE_VALUE 66 -#define LOAD_ATTR_MODULE 67 -#define LOAD_ATTR_PROPERTY 70 -#define LOAD_ATTR_SLOT 72 -#define LOAD_ATTR_WITH_HINT 73 -#define LOAD_ATTR_METHOD_LAZY_DICT 76 -#define LOAD_ATTR_METHOD_NO_DICT 77 -#define LOAD_ATTR_METHOD_WITH_VALUES 78 -#define LOAD_CONST__LOAD_FAST 79 -#define LOAD_FAST__LOAD_CONST 80 -#define LOAD_FAST__LOAD_FAST 81 -#define LOAD_GLOBAL_BUILTIN 82 -#define LOAD_GLOBAL_MODULE 84 -#define STORE_ATTR_INSTANCE_VALUE 86 -#define STORE_ATTR_SLOT 87 -#define STORE_ATTR_WITH_HINT 88 -#define STORE_FAST__LOAD_FAST 111 -#define STORE_FAST__STORE_FAST 112 -#define STORE_SUBSCR_DICT 113 -#define STORE_SUBSCR_LIST_INT 141 -#define UNPACK_SEQUENCE_LIST 143 -#define UNPACK_SEQUENCE_TUPLE 153 -#define UNPACK_SEQUENCE_TWO_TUPLE 154 -#define SEND_GEN 158 -#define DO_TRACING 255 +#define BINARY_OP_ADD_FLOAT 6 +#define BINARY_OP_ADD_INT 7 +#define BINARY_OP_ADD_UNICODE 8 +#define BINARY_OP_INPLACE_ADD_UNICODE 10 +#define BINARY_OP_MULTIPLY_FLOAT 13 +#define BINARY_OP_MULTIPLY_INT 14 +#define BINARY_OP_SUBTRACT_FLOAT 16 +#define BINARY_OP_SUBTRACT_INT 18 +#define BINARY_SUBSCR_DICT 19 +#define BINARY_SUBSCR_GETITEM 20 +#define BINARY_SUBSCR_LIST_INT 21 +#define BINARY_SUBSCR_TUPLE_INT 22 +#define CALL_PY_EXACT_ARGS 23 +#define CALL_PY_WITH_DEFAULTS 24 +#define CALL_BOUND_METHOD_EXACT_ARGS 28 +#define CALL_BUILTIN_CLASS 29 +#define CALL_BUILTIN_FAST_WITH_KEYWORDS 34 +#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 38 +#define CALL_NO_KW_BUILTIN_FAST 39 +#define CALL_NO_KW_BUILTIN_O 40 +#define CALL_NO_KW_ISINSTANCE 41 +#define CALL_NO_KW_LEN 42 +#define CALL_NO_KW_LIST_APPEND 43 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 44 +#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 45 +#define CALL_NO_KW_METHOD_DESCRIPTOR_O 46 +#define CALL_NO_KW_STR_1 47 +#define CALL_NO_KW_TUPLE_1 48 +#define CALL_NO_KW_TYPE_1 56 +#define COMPARE_OP_FLOAT 57 +#define COMPARE_OP_INT 58 +#define COMPARE_OP_STR 59 +#define FOR_ITER_LIST 62 +#define FOR_ITER_TUPLE 63 +#define FOR_ITER_RANGE 64 +#define FOR_ITER_GEN 65 +#define LOAD_ATTR_CLASS 66 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 67 +#define LOAD_ATTR_INSTANCE_VALUE 70 +#define LOAD_ATTR_MODULE 72 +#define LOAD_ATTR_PROPERTY 73 +#define LOAD_ATTR_SLOT 76 +#define LOAD_ATTR_WITH_HINT 77 +#define LOAD_ATTR_METHOD_LAZY_DICT 78 +#define LOAD_ATTR_METHOD_NO_DICT 79 +#define LOAD_ATTR_METHOD_WITH_VALUES 80 +#define LOAD_CONST__LOAD_FAST 81 +#define LOAD_FAST__LOAD_CONST 82 +#define LOAD_FAST__LOAD_FAST 84 +#define LOAD_GLOBAL_BUILTIN 86 +#define LOAD_GLOBAL_MODULE 87 +#define STORE_ATTR_INSTANCE_VALUE 88 +#define STORE_ATTR_SLOT 111 +#define STORE_ATTR_WITH_HINT 112 +#define STORE_FAST__LOAD_FAST 113 +#define STORE_FAST__STORE_FAST 141 +#define STORE_SUBSCR_DICT 143 +#define STORE_SUBSCR_LIST_INT 153 +#define UNPACK_SEQUENCE_LIST 154 +#define UNPACK_SEQUENCE_TUPLE 158 +#define UNPACK_SEQUENCE_TWO_TUPLE 159 +#define SEND_GEN 160 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index de6c434450fc..c0c757d94d87 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -439,6 +439,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12a7 3523 (Convert COMPARE_AND_BRANCH back to COMPARE_OP) # Python 3.12a7 3524 (Shrink the BINARY_SUBSCR caches) # Python 3.12b1 3525 (Shrink the CALL caches) +# Python 3.12a7 3526 (Add instrumentation support) # Python 3.13 will start with 3550 @@ -455,7 +456,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3525).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3526).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/opcode.py b/Lib/opcode.py index b62dfa1bcb42..dd739e5dd3f6 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -83,6 +83,7 @@ def pseudo_op(name, op, real_ops): def_op('INTERPRETER_EXIT', 3) def_op('END_FOR', 4) +def_op('END_SEND', 5) def_op('NOP', 9) @@ -91,6 +92,10 @@ def pseudo_op(name, op, real_ops): def_op('UNARY_INVERT', 15) +# We reserve 17 as it is the initial value for the specializing counter +# This helps us catch cases where we attempt to execute a cache. +def_op('RESERVED', 17) + def_op('BINARY_SUBSCR', 25) def_op('BINARY_SLICE', 26) def_op('STORE_SLICE', 27) @@ -221,6 +226,28 @@ def pseudo_op(name, op, real_ops): def_op('CALL_INTRINSIC_1', 173) def_op('CALL_INTRINSIC_2', 174) +# Instrumented instructions +MIN_INSTRUMENTED_OPCODE = 238 + +def_op('INSTRUMENTED_POP_JUMP_IF_NONE', 238) +def_op('INSTRUMENTED_POP_JUMP_IF_NOT_NONE', 239) +def_op('INSTRUMENTED_RESUME', 240) +def_op('INSTRUMENTED_CALL', 241) +def_op('INSTRUMENTED_RETURN_VALUE', 242) +def_op('INSTRUMENTED_YIELD_VALUE', 243) +def_op('INSTRUMENTED_CALL_FUNCTION_EX', 244) +def_op('INSTRUMENTED_JUMP_FORWARD', 245) +def_op('INSTRUMENTED_JUMP_BACKWARD', 246) +def_op('INSTRUMENTED_RETURN_CONST', 247) +def_op('INSTRUMENTED_FOR_ITER', 248) +def_op('INSTRUMENTED_POP_JUMP_IF_FALSE', 249) +def_op('INSTRUMENTED_POP_JUMP_IF_TRUE', 250) +def_op('INSTRUMENTED_END_FOR', 251) +def_op('INSTRUMENTED_END_SEND', 252) +def_op('INSTRUMENTED_INSTRUCTION', 253) +def_op('INSTRUMENTED_LINE', 254) +# 255 is reserved + hasarg.extend([op for op in opmap.values() if op >= HAVE_ARGUMENT]) MIN_PSEUDO_OPCODE = 256 diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py index 31f3c53992db..7640c6fb57d4 100644 --- a/Lib/test/test__opcode.py +++ b/Lib/test/test__opcode.py @@ -20,6 +20,8 @@ def test_stack_effect(self): # All defined opcodes has_arg = dis.hasarg for name, code in filter(lambda item: item[0] not in dis.deoptmap, dis.opmap.items()): + if code >= opcode.MIN_INSTRUMENTED_OPCODE: + continue with self.subTest(opname=name): if code not in has_arg: stack_effect(code) @@ -47,6 +49,8 @@ def test_stack_effect_jump(self): has_exc = dis.hasexc has_jump = dis.hasjabs + dis.hasjrel for name, code in filter(lambda item: item[0] not in dis.deoptmap, dis.opmap.items()): + if code >= opcode.MIN_INSTRUMENTED_OPCODE: + continue with self.subTest(opname=name): if code not in has_arg: common = stack_effect(code) diff --git a/Lib/test/test_bdb.py b/Lib/test/test_bdb.py index 042c2daea7f7..fc4b80943163 100644 --- a/Lib/test/test_bdb.py +++ b/Lib/test/test_bdb.py @@ -433,8 +433,9 @@ def __exit__(self, type_=None, value=None, traceback=None): not_empty = '' if self.tracer.set_list: not_empty += 'All paired tuples have not been processed, ' - not_empty += ('the last one was number %d' % + not_empty += ('the last one was number %d\n' % self.tracer.expect_set_no) + not_empty += repr(self.tracer.set_list) # Make a BdbNotExpectedError a unittest failure. if type_ is not None and issubclass(BdbNotExpectedError, type_): diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py index 7543c9ab3421..ecb3525a9284 100644 --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -349,14 +349,14 @@ def test_invalid_bytecode(self): def foo(): pass - # assert that opcode 238 is invalid - self.assertEqual(opname[238], '<238>') + # assert that opcode 229 is invalid + self.assertEqual(opname[229], '<229>') - # change first opcode to 0xee (=238) + # change first opcode to 0xeb (=229) foo.__code__ = foo.__code__.replace( - co_code=b'\xee' + foo.__code__.co_code[1:]) + co_code=b'\xe5' + foo.__code__.co_code[1:]) - msg = f"unknown opcode 238" + msg = f"unknown opcode 229" with self.assertRaisesRegex(SystemError, msg): foo() diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 4a2144743f65..0a60a979614d 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -479,8 +479,7 @@ async def _asyncwith(c): YIELD_VALUE 2 RESUME 3 JUMP_BACKWARD_NO_INTERRUPT 5 (to 14) - >> SWAP 2 - POP_TOP + >> END_SEND POP_TOP %3d LOAD_CONST 1 (1) @@ -492,11 +491,11 @@ async def _asyncwith(c): CALL 2 GET_AWAITABLE 2 LOAD_CONST 0 (None) - >> SEND 3 (to 62) + >> SEND 3 (to 60) YIELD_VALUE 2 RESUME 3 - JUMP_BACKWARD_NO_INTERRUPT 5 (to 52) - >> POP_TOP + JUMP_BACKWARD_NO_INTERRUPT 5 (to 50) + >> END_SEND POP_TOP %3d LOAD_CONST 2 (2) @@ -504,21 +503,20 @@ async def _asyncwith(c): RETURN_CONST 0 (None) %3d >> CLEANUP_THROW - JUMP_BACKWARD 26 (to 24) + JUMP_BACKWARD 25 (to 24) >> CLEANUP_THROW - JUMP_BACKWARD 9 (to 62) + JUMP_BACKWARD 9 (to 60) >> PUSH_EXC_INFO WITH_EXCEPT_START GET_AWAITABLE 2 LOAD_CONST 0 (None) - >> SEND 4 (to 100) + >> SEND 4 (to 98) YIELD_VALUE 3 RESUME 3 - JUMP_BACKWARD_NO_INTERRUPT 5 (to 88) + JUMP_BACKWARD_NO_INTERRUPT 5 (to 86) >> CLEANUP_THROW - >> SWAP 2 - POP_TOP - POP_JUMP_IF_TRUE 1 (to 108) + >> END_SEND + POP_JUMP_IF_TRUE 1 (to 104) RERAISE 2 >> POP_TOP POP_EXCEPT @@ -878,9 +876,9 @@ def test_boundaries(self): def test_widths(self): long_opcodes = set(['JUMP_BACKWARD_NO_INTERRUPT', - ]) + 'INSTRUMENTED_CALL_FUNCTION_EX']) for opcode, opname in enumerate(dis.opname): - if opname in long_opcodes: + if opname in long_opcodes or opname.startswith("INSTRUMENTED"): continue with self.subTest(opname=opname): width = dis._OPNAME_WIDTH diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py new file mode 100644 index 000000000000..4aad3da61b6b --- /dev/null +++ b/Lib/test/test_monitoring.py @@ -0,0 +1,1044 @@ +"""Test suite for the sys.monitoring.""" + +import collections +import functools +import operator +import sys +import types +import unittest + + +PAIR = (0,1) + +def f1(): + pass + +def f2(): + len([]) + sys.getsizeof(0) + +def floop(): + for item in PAIR: + pass + +def gen(): + yield + yield + +def g1(): + for _ in gen(): + pass + +TEST_TOOL = 2 +TEST_TOOL2 = 3 +TEST_TOOL3 = 4 + +class MonitoringBasicTest(unittest.TestCase): + + def test_has_objects(self): + m = sys.monitoring + m.events + m.use_tool_id + m.free_tool_id + m.get_tool + m.get_events + m.set_events + m.get_local_events + m.set_local_events + m.register_callback + m.restart_events + m.DISABLE + m.MISSING + m.events.NO_EVENTS + + def test_tool(self): + sys.monitoring.use_tool_id(TEST_TOOL, "MonitoringTest.Tool") + self.assertEqual(sys.monitoring.get_tool(TEST_TOOL), "MonitoringTest.Tool") + sys.monitoring.set_events(TEST_TOOL, 15) + self.assertEqual(sys.monitoring.get_events(TEST_TOOL), 15) + sys.monitoring.set_events(TEST_TOOL, 0) + with self.assertRaises(ValueError): + sys.monitoring.set_events(TEST_TOOL, sys.monitoring.events.C_RETURN) + with self.assertRaises(ValueError): + sys.monitoring.set_events(TEST_TOOL, sys.monitoring.events.C_RAISE) + sys.monitoring.free_tool_id(TEST_TOOL) + self.assertEqual(sys.monitoring.get_tool(TEST_TOOL), None) + with self.assertRaises(ValueError): + sys.monitoring.set_events(TEST_TOOL, sys.monitoring.events.CALL) + + +class MonitoringTestBase: + + def setUp(self): + # Check that a previous test hasn't left monitoring on. + for tool in range(6): + self.assertEqual(sys.monitoring.get_events(tool), 0) + self.assertIs(sys.monitoring.get_tool(TEST_TOOL), None) + self.assertIs(sys.monitoring.get_tool(TEST_TOOL2), None) + self.assertIs(sys.monitoring.get_tool(TEST_TOOL3), None) + sys.monitoring.use_tool_id(TEST_TOOL, "test " + self.__class__.__name__) + sys.monitoring.use_tool_id(TEST_TOOL2, "test2 " + self.__class__.__name__) + sys.monitoring.use_tool_id(TEST_TOOL3, "test3 " + self.__class__.__name__) + + def tearDown(self): + # Check that test hasn't left monitoring on. + for tool in range(6): + self.assertEqual(sys.monitoring.get_events(tool), 0) + sys.monitoring.free_tool_id(TEST_TOOL) + sys.monitoring.free_tool_id(TEST_TOOL2) + sys.monitoring.free_tool_id(TEST_TOOL3) + + +class MonitoringCountTest(MonitoringTestBase, unittest.TestCase): + + def check_event_count(self, func, event, expected): + + class Counter: + def __init__(self): + self.count = 0 + def __call__(self, *args): + self.count += 1 + + counter = Counter() + sys.monitoring.register_callback(TEST_TOOL, event, counter) + if event == E.C_RETURN or event == E.C_RAISE: + sys.monitoring.set_events(TEST_TOOL, E.CALL) + else: + sys.monitoring.set_events(TEST_TOOL, event) + self.assertEqual(counter.count, 0) + counter.count = 0 + func() + self.assertEqual(counter.count, expected) + prev = sys.monitoring.register_callback(TEST_TOOL, event, None) + counter.count = 0 + func() + self.assertEqual(counter.count, 0) + self.assertEqual(prev, counter) + sys.monitoring.set_events(TEST_TOOL, 0) + + def test_start_count(self): + self.check_event_count(f1, E.PY_START, 1) + + def test_resume_count(self): + self.check_event_count(g1, E.PY_RESUME, 2) + + def test_return_count(self): + self.check_event_count(f1, E.PY_RETURN, 1) + + def test_call_count(self): + self.check_event_count(f2, E.CALL, 3) + + def test_c_return_count(self): + self.check_event_count(f2, E.C_RETURN, 2) + + +E = sys.monitoring.events + +SIMPLE_EVENTS = [ + (E.PY_START, "start"), + (E.PY_RESUME, "resume"), + (E.PY_RETURN, "return"), + (E.PY_YIELD, "yield"), + (E.JUMP, "jump"), + (E.BRANCH, "branch"), + (E.RAISE, "raise"), + (E.PY_UNWIND, "unwind"), + (E.EXCEPTION_HANDLED, "exception_handled"), + (E.C_RAISE, "c_raise"), + (E.C_RETURN, "c_return"), +] + +SIMPLE_EVENT_SET = functools.reduce(operator.or_, [ev for (ev, _) in SIMPLE_EVENTS], 0) | E.CALL + + +def just_pass(): + pass + +just_pass.events = [ + "py_call", + "start", + "return", +] + +def just_raise(): + raise Exception + +just_raise.events = [ + 'py_call', + "start", + "raise", + "unwind", +] + +def just_call(): + len([]) + +just_call.events = [ + 'py_call', + "start", + "c_call", + "c_return", + "return", +] + +def caught(): + try: + 1/0 + except Exception: + pass + +caught.events = [ + 'py_call', + "start", + "raise", + "exception_handled", + "branch", + "return", +] + +def nested_call(): + just_pass() + +nested_call.events = [ + "py_call", + "start", + "py_call", + "start", + "return", + "return", +] + +PY_CALLABLES = (types.FunctionType, types.MethodType) + +class MonitoringEventsBase(MonitoringTestBase): + + def gather_events(self, func): + events = [] + for event, event_name in SIMPLE_EVENTS: + def record(*args, event_name=event_name): + events.append(event_name) + sys.monitoring.register_callback(TEST_TOOL, event, record) + def record_call(code, offset, obj, arg): + if isinstance(obj, PY_CALLABLES): + events.append("py_call") + else: + events.append("c_call") + sys.monitoring.register_callback(TEST_TOOL, E.CALL, record_call) + sys.monitoring.set_events(TEST_TOOL, SIMPLE_EVENT_SET) + events = [] + try: + func() + except: + pass + sys.monitoring.set_events(TEST_TOOL, 0) + #Remove the final event, the call to `sys.monitoring.set_events` + events = events[:-1] + return events + + def check_events(self, func, expected=None): + events = self.gather_events(func) + if expected is None: + expected = func.events + self.assertEqual(events, expected) + + +class MonitoringEventsTest(MonitoringEventsBase, unittest.TestCase): + + def test_just_pass(self): + self.check_events(just_pass) + + def test_just_raise(self): + try: + self.check_events(just_raise) + except Exception: + pass + self.assertEqual(sys.monitoring.get_events(TEST_TOOL), 0) + + def test_just_call(self): + self.check_events(just_call) + + def test_caught(self): + self.check_events(caught) + + def test_nested_call(self): + self.check_events(nested_call) + +UP_EVENTS = (E.C_RETURN, E.C_RAISE, E.PY_RETURN, E.PY_UNWIND, E.PY_YIELD) +DOWN_EVENTS = (E.PY_START, E.PY_RESUME) + +from test.profilee import testfunc + +class SimulateProfileTest(MonitoringEventsBase, unittest.TestCase): + + def test_balanced(self): + events = self.gather_events(testfunc) + c = collections.Counter(events) + self.assertEqual(c["c_call"], c["c_return"]) + self.assertEqual(c["start"], c["return"] + c["unwind"]) + self.assertEqual(c["raise"], c["exception_handled"] + c["unwind"]) + + def test_frame_stack(self): + self.maxDiff = None + stack = [] + errors = [] + seen = set() + def up(*args): + frame = sys._getframe(1) + if not stack: + errors.append("empty") + else: + expected = stack.pop() + if frame != expected: + errors.append(f" Popping {frame} expected {expected}") + def down(*args): + frame = sys._getframe(1) + stack.append(frame) + seen.add(frame.f_code) + def call(code, offset, callable, arg): + if not isinstance(callable, PY_CALLABLES): + stack.append(sys._getframe(1)) + for event in UP_EVENTS: + sys.monitoring.register_callback(TEST_TOOL, event, up) + for event in DOWN_EVENTS: + sys.monitoring.register_callback(TEST_TOOL, event, down) + sys.monitoring.register_callback(TEST_TOOL, E.CALL, call) + sys.monitoring.set_events(TEST_TOOL, SIMPLE_EVENT_SET) + testfunc() + sys.monitoring.set_events(TEST_TOOL, 0) + self.assertEqual(errors, []) + self.assertEqual(stack, [sys._getframe()]) + self.assertEqual(len(seen), 9) + + +class CounterWithDisable: + + def __init__(self): + self.disable = False + self.count = 0 + + def __call__(self, *args): + self.count += 1 + if self.disable: + return sys.monitoring.DISABLE + + +class RecorderWithDisable: + + def __init__(self, events): + self.disable = False + self.events = events + + def __call__(self, code, event): + self.events.append(event) + if self.disable: + return sys.monitoring.DISABLE + + +class MontoringDisableAndRestartTest(MonitoringTestBase, unittest.TestCase): + + def test_disable(self): + try: + counter = CounterWithDisable() + sys.monitoring.register_callback(TEST_TOOL, E.PY_START, counter) + sys.monitoring.set_events(TEST_TOOL, E.PY_START) + self.assertEqual(counter.count, 0) + counter.count = 0 + f1() + self.assertEqual(counter.count, 1) + counter.disable = True + counter.count = 0 + f1() + self.assertEqual(counter.count, 1) + counter.count = 0 + f1() + self.assertEqual(counter.count, 0) + sys.monitoring.set_events(TEST_TOOL, 0) + finally: + sys.monitoring.restart_events() + + def test_restart(self): + try: + counter = CounterWithDisable() + sys.monitoring.register_callback(TEST_TOOL, E.PY_START, counter) + sys.monitoring.set_events(TEST_TOOL, E.PY_START) + counter.disable = True + f1() + counter.count = 0 + f1() + self.assertEqual(counter.count, 0) + sys.monitoring.restart_events() + counter.count = 0 + f1() + self.assertEqual(counter.count, 1) + sys.monitoring.set_events(TEST_TOOL, 0) + finally: + sys.monitoring.restart_events() + + +class MultipleMonitorsTest(MonitoringTestBase, unittest.TestCase): + + def test_two_same(self): + try: + self.assertEqual(sys.monitoring._all_events(), {}) + counter1 = CounterWithDisable() + counter2 = CounterWithDisable() + sys.monitoring.register_callback(TEST_TOOL, E.PY_START, counter1) + sys.monitoring.register_callback(TEST_TOOL2, E.PY_START, counter2) + sys.monitoring.set_events(TEST_TOOL, E.PY_START) + sys.monitoring.set_events(TEST_TOOL2, E.PY_START) + self.assertEqual(sys.monitoring.get_events(TEST_TOOL), E.PY_START) + self.assertEqual(sys.monitoring.get_events(TEST_TOOL2), E.PY_START) + self.assertEqual(sys.monitoring._all_events(), {'PY_START': (1 << TEST_TOOL) | (1 << TEST_TOOL2)}) + counter1.count = 0 + counter2.count = 0 + f1() + count1 = counter1.count + count2 = counter2.count + self.assertEqual((count1, count2), (1, 1)) + finally: + sys.monitoring.set_events(TEST_TOOL, 0) + sys.monitoring.set_events(TEST_TOOL2, 0) + sys.monitoring.register_callback(TEST_TOOL, E.PY_START, None) + sys.monitoring.register_callback(TEST_TOOL2, E.PY_START, None) + self.assertEqual(sys.monitoring._all_events(), {}) + + def test_three_same(self): + try: + self.assertEqual(sys.monitoring._all_events(), {}) + counter1 = CounterWithDisable() + counter2 = CounterWithDisable() + counter3 = CounterWithDisable() + sys.monitoring.register_callback(TEST_TOOL, E.PY_START, counter1) + sys.monitoring.register_callback(TEST_TOOL2, E.PY_START, counter2) + sys.monitoring.register_callback(TEST_TOOL3, E.PY_START, counter3) + sys.monitoring.set_events(TEST_TOOL, E.PY_START) + sys.monitoring.set_events(TEST_TOOL2, E.PY_START) + sys.monitoring.set_events(TEST_TOOL3, E.PY_START) + self.assertEqual(sys.monitoring.get_events(TEST_TOOL), E.PY_START) + self.assertEqual(sys.monitoring.get_events(TEST_TOOL2), E.PY_START) + self.assertEqual(sys.monitoring.get_events(TEST_TOOL3), E.PY_START) + self.assertEqual(sys.monitoring._all_events(), {'PY_START': (1 << TEST_TOOL) | (1 << TEST_TOOL2) | (1 << TEST_TOOL3)}) + counter1.count = 0 + counter2.count = 0 + counter3.count = 0 + f1() + count1 = counter1.count + count2 = counter2.count + count3 = counter3.count + self.assertEqual((count1, count2, count3), (1, 1, 1)) + finally: + sys.monitoring.set_events(TEST_TOOL, 0) + sys.monitoring.set_events(TEST_TOOL2, 0) + sys.monitoring.set_events(TEST_TOOL3, 0) + sys.monitoring.register_callback(TEST_TOOL, E.PY_START, None) + sys.monitoring.register_callback(TEST_TOOL2, E.PY_START, None) + sys.monitoring.register_callback(TEST_TOOL3, E.PY_START, None) + self.assertEqual(sys.monitoring._all_events(), {}) + + def test_two_different(self): + try: + self.assertEqual(sys.monitoring._all_events(), {}) + counter1 = CounterWithDisable() + counter2 = CounterWithDisable() + sys.monitoring.register_callback(TEST_TOOL, E.PY_START, counter1) + sys.monitoring.register_callback(TEST_TOOL2, E.PY_RETURN, counter2) + sys.monitoring.set_events(TEST_TOOL, E.PY_START) + sys.monitoring.set_events(TEST_TOOL2, E.PY_RETURN) + self.assertEqual(sys.monitoring.get_events(TEST_TOOL), E.PY_START) + self.assertEqual(sys.monitoring.get_events(TEST_TOOL2), E.PY_RETURN) + self.assertEqual(sys.monitoring._all_events(), {'PY_START': 1 << TEST_TOOL, 'PY_RETURN': 1 << TEST_TOOL2}) + counter1.count = 0 + counter2.count = 0 + f1() + count1 = counter1.count + count2 = counter2.count + self.assertEqual((count1, count2), (1, 1)) + finally: + sys.monitoring.set_events(TEST_TOOL, 0) + sys.monitoring.set_events(TEST_TOOL2, 0) + sys.monitoring.register_callback(TEST_TOOL, E.PY_START, None) + sys.monitoring.register_callback(TEST_TOOL2, E.PY_RETURN, None) + self.assertEqual(sys.monitoring._all_events(), {}) + + def test_two_with_disable(self): + try: + self.assertEqual(sys.monitoring._all_events(), {}) + counter1 = CounterWithDisable() + counter2 = CounterWithDisable() + sys.monitoring.register_callback(TEST_TOOL, E.PY_START, counter1) + sys.monitoring.register_callback(TEST_TOOL2, E.PY_START, counter2) + sys.monitoring.set_events(TEST_TOOL, E.PY_START) + sys.monitoring.set_events(TEST_TOOL2, E.PY_START) + self.assertEqual(sys.monitoring.get_events(TEST_TOOL), E.PY_START) + self.assertEqual(sys.monitoring.get_events(TEST_TOOL2), E.PY_START) + self.assertEqual(sys.monitoring._all_events(), {'PY_START': (1 << TEST_TOOL) | (1 << TEST_TOOL2)}) + counter1.count = 0 + counter2.count = 0 + counter1.disable = True + f1() + count1 = counter1.count + count2 = counter2.count + self.assertEqual((count1, count2), (1, 1)) + counter1.count = 0 + counter2.count = 0 + f1() + count1 = counter1.count + count2 = counter2.count + self.assertEqual((count1, count2), (0, 1)) + finally: + sys.monitoring.set_events(TEST_TOOL, 0) + sys.monitoring.set_events(TEST_TOOL2, 0) + sys.monitoring.register_callback(TEST_TOOL, E.PY_START, None) + sys.monitoring.register_callback(TEST_TOOL2, E.PY_START, None) + self.assertEqual(sys.monitoring._all_events(), {}) + sys.monitoring.restart_events() + +class LineMonitoringTest(MonitoringTestBase, unittest.TestCase): + + def test_lines_single(self): + try: + self.assertEqual(sys.monitoring._all_events(), {}) + events = [] + recorder = RecorderWithDisable(events) + sys.monitoring.register_callback(TEST_TOOL, E.LINE, recorder) + sys.monitoring.set_events(TEST_TOOL, E.LINE) + f1() + sys.monitoring.set_events(TEST_TOOL, 0) + sys.monitoring.register_callback(TEST_TOOL, E.LINE, None) + start = LineMonitoringTest.test_lines_single.__code__.co_firstlineno + self.assertEqual(events, [start+7, 14, start+8]) + finally: + sys.monitoring.set_events(TEST_TOOL, 0) + sys.monitoring.register_callback(TEST_TOOL, E.LINE, None) + self.assertEqual(sys.monitoring._all_events(), {}) + sys.monitoring.restart_events() + + def test_lines_loop(self): + try: + self.assertEqual(sys.monitoring._all_events(), {}) + events = [] + recorder = RecorderWithDisable(events) + sys.monitoring.register_callback(TEST_TOOL, E.LINE, recorder) + sys.monitoring.set_events(TEST_TOOL, E.LINE) + floop() + sys.monitoring.set_events(TEST_TOOL, 0) + sys.monitoring.register_callback(TEST_TOOL, E.LINE, None) + start = LineMonitoringTest.test_lines_loop.__code__.co_firstlineno + self.assertEqual(events, [start+7, 21, 22, 22, 21, start+8]) + finally: + sys.monitoring.set_events(TEST_TOOL, 0) + sys.monitoring.register_callback(TEST_TOOL, E.LINE, None) + self.assertEqual(sys.monitoring._all_events(), {}) + sys.monitoring.restart_events() + + def test_lines_two(self): + try: + self.assertEqual(sys.monitoring._all_events(), {}) + events = [] + recorder = RecorderWithDisable(events) + events2 = [] + recorder2 = RecorderWithDisable(events2) + sys.monitoring.register_callback(TEST_TOOL, E.LINE, recorder) + sys.monitoring.register_callback(TEST_TOOL2, E.LINE, recorder2) + sys.monitoring.set_events(TEST_TOOL, E.LINE); sys.monitoring.set_events(TEST_TOOL2, E.LINE) + f1() + sys.monitoring.set_events(TEST_TOOL, 0); sys.monitoring.set_events(TEST_TOOL2, 0) + sys.monitoring.register_callback(TEST_TOOL, E.LINE, None) + sys.monitoring.register_callback(TEST_TOOL2, E.LINE, None) + start = LineMonitoringTest.test_lines_two.__code__.co_firstlineno + expected = [start+10, 14, start+11] + self.assertEqual(events, expected) + self.assertEqual(events2, expected) + finally: + sys.monitoring.set_events(TEST_TOOL, 0) + sys.monitoring.set_events(TEST_TOOL2, 0) + sys.monitoring.register_callback(TEST_TOOL, E.LINE, None) + sys.monitoring.register_callback(TEST_TOOL2, E.LINE, None) + self.assertEqual(sys.monitoring._all_events(), {}) + sys.monitoring.restart_events() + + def check_lines(self, func, expected, tool=TEST_TOOL): + try: + self.assertEqual(sys.monitoring._all_events(), {}) + events = [] + recorder = RecorderWithDisable(events) + sys.monitoring.register_callback(tool, E.LINE, recorder) + sys.monitoring.set_events(tool, E.LINE) + func() + sys.monitoring.set_events(tool, 0) + sys.monitoring.register_callback(tool, E.LINE, None) + lines = [ line - func.__code__.co_firstlineno for line in events[1:-1] ] + self.assertEqual(lines, expected) + finally: + sys.monitoring.set_events(tool, 0) + + + def test_linear(self): + + def func(): + line = 1 + line = 2 + line = 3 + line = 4 + line = 5 + + self.check_lines(func, [1,2,3,4,5]) + + def test_branch(self): + def func(): + if "true".startswith("t"): + line = 2 + line = 3 + else: + line = 5 + line = 6 + + self.check_lines(func, [1,2,3,6]) + + def test_try_except(self): + + def func1(): + try: + line = 2 + line = 3 + except: + line = 5 + line = 6 + + self.check_lines(func1, [1,2,3,6]) + + def func2(): + try: + line = 2 + raise 3 + except: + line = 5 + line = 6 + + self.check_lines(func2, [1,2,3,4,5,6]) + + +class ExceptionRecorder: + + event_type = E.RAISE + + def __init__(self, events): + self.events = events + + def __call__(self, code, offset, exc): + self.events.append(("raise", type(exc))) + +class CheckEvents(MonitoringTestBase, unittest.TestCase): + + def check_events(self, func, expected, tool=TEST_TOOL, recorders=(ExceptionRecorder,)): + try: + self.assertEqual(sys.monitoring._all_events(), {}) + event_list = [] + all_events = 0 + for recorder in recorders: + ev = recorder.event_type + sys.monitoring.register_callback(tool, ev, recorder(event_list)) + all_events |= ev + sys.monitoring.set_events(tool, all_events) + func() + sys.monitoring.set_events(tool, 0) + for recorder in recorders: + sys.monitoring.register_callback(tool, recorder.event_type, None) + self.assertEqual(event_list, expected) + finally: + sys.monitoring.set_events(tool, 0) + for recorder in recorders: + sys.monitoring.register_callback(tool, recorder.event_type, None) + +class StopiterationRecorder(ExceptionRecorder): + + event_type = E.STOP_ITERATION + +class ExceptionMontoringTest(CheckEvents): + + recorder = ExceptionRecorder + + def test_simple_try_except(self): + + def func1(): + try: + line = 2 + raise KeyError + except: + line = 5 + line = 6 + + self.check_events(func1, [("raise", KeyError)]) + + def gen(): + yield 1 + return 2 + + def implicit_stop_iteration(): + for _ in gen(): + pass + + self.check_events(implicit_stop_iteration, [("raise", StopIteration)], recorders=(StopiterationRecorder,)) + +class LineRecorder: + + event_type = E.LINE + + + def __init__(self, events): + self.events = events + + def __call__(self, code, line): + self.events.append(("line", code.co_name, line - code.co_firstlineno)) + +class CallRecorder: + + event_type = E.CALL + + def __init__(self, events): + self.events = events + + def __call__(self, code, offset, func, arg): + self.events.append(("call", func.__name__, arg)) + +class CEventRecorder: + + def __init__(self, events): + self.events = events + + def __call__(self, code, offset, func, arg): + self.events.append((self.event_name, func.__name__, arg)) + +class CReturnRecorder(CEventRecorder): + + event_type = E.C_RETURN + event_name = "C return" + +class CRaiseRecorder(CEventRecorder): + + event_type = E.C_RAISE + event_name = "C raise" + +MANY_RECORDERS = ExceptionRecorder, CallRecorder, LineRecorder, CReturnRecorder, CRaiseRecorder + +class TestManyEvents(CheckEvents): + + def test_simple(self): + + def func1(): + line1 = 1 + line2 = 2 + line3 = 3 + + self.check_events(func1, recorders = MANY_RECORDERS, expected = [ + ('line', 'check_events', 10), + ('call', 'func1', sys.monitoring.MISSING), + ('line', 'func1', 1), + ('line', 'func1', 2), + ('line', 'func1', 3), + ('line', 'check_events', 11), + ('call', 'set_events', 2)]) + + def test_c_call(self): + + def func2(): + line1 = 1 + [].append(2) + line3 = 3 + + self.check_events(func2, recorders = MANY_RECORDERS, expected = [ + ('line', 'check_events', 10), + ('call', 'func2', sys.monitoring.MISSING), + ('line', 'func2', 1), + ('line', 'func2', 2), + ('call', 'append', [2]), + ('C return', 'append', [2]), + ('line', 'func2', 3), + ('line', 'check_events', 11), + ('call', 'set_events', 2)]) + + def test_try_except(self): + + def func3(): + try: + line = 2 + raise KeyError + except: + line = 5 + line = 6 + + self.check_events(func3, recorders = MANY_RECORDERS, expected = [ + ('line', 'check_events', 10), + ('call', 'func3', sys.monitoring.MISSING), + ('line', 'func3', 1), + ('line', 'func3', 2), + ('line', 'func3', 3), + ('raise', KeyError), + ('line', 'func3', 4), + ('line', 'func3', 5), + ('line', 'func3', 6), + ('line', 'check_events', 11), + ('call', 'set_events', 2)]) + +class InstructionRecorder: + + event_type = E.INSTRUCTION + + def __init__(self, events): + self.events = events + + def __call__(self, code, offset): + # Filter out instructions in check_events to lower noise + if code.co_name != "check_events": + self.events.append(("instruction", code.co_name, offset)) + + +LINE_AND_INSTRUCTION_RECORDERS = InstructionRecorder, LineRecorder + +class TestLineAndInstructionEvents(CheckEvents): + maxDiff = None + + def test_simple(self): + + def func1(): + line1 = 1 + line2 = 2 + line3 = 3 + + self.check_events(func1, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [ + ('line', 'check_events', 10), + ('line', 'func1', 1), + ('instruction', 'func1', 2), + ('instruction', 'func1', 4), + ('line', 'func1', 2), + ('instruction', 'func1', 6), + ('instruction', 'func1', 8), + ('line', 'func1', 3), + ('instruction', 'func1', 10), + ('instruction', 'func1', 12), + ('instruction', 'func1', 14), + ('line', 'check_events', 11)]) + + def test_c_call(self): + + def func2(): + line1 = 1 + [].append(2) + line3 = 3 + + self.check_events(func2, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [ + ('line', 'check_events', 10), + ('line', 'func2', 1), + ('instruction', 'func2', 2), + ('instruction', 'func2', 4), + ('line', 'func2', 2), + ('instruction', 'func2', 6), + ('instruction', 'func2', 8), + ('instruction', 'func2', 28), + ('instruction', 'func2', 30), + ('instruction', 'func2', 38), + ('line', 'func2', 3), + ('instruction', 'func2', 40), + ('instruction', 'func2', 42), + ('instruction', 'func2', 44), + ('line', 'check_events', 11)]) + + def test_try_except(self): + + def func3(): + try: + line = 2 + raise KeyError + except: + line = 5 + line = 6 + + self.check_events(func3, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [ + ('line', 'check_events', 10), + ('line', 'func3', 1), + ('instruction', 'func3', 2), + ('line', 'func3', 2), + ('instruction', 'func3', 4), + ('instruction', 'func3', 6), + ('line', 'func3', 3), + ('instruction', 'func3', 8), + ('instruction', 'func3', 18), + ('instruction', 'func3', 20), + ('line', 'func3', 4), + ('instruction', 'func3', 22), + ('line', 'func3', 5), + ('instruction', 'func3', 24), + ('instruction', 'func3', 26), + ('instruction', 'func3', 28), + ('line', 'func3', 6), + ('instruction', 'func3', 30), + ('instruction', 'func3', 32), + ('instruction', 'func3', 34), + ('line', 'check_events', 11)]) + +class TestInstallIncrementallly(MonitoringTestBase, unittest.TestCase): + + def check_events(self, func, must_include, tool=TEST_TOOL, recorders=(ExceptionRecorder,)): + try: + self.assertEqual(sys.monitoring._all_events(), {}) + event_list = [] + all_events = 0 + for recorder in recorders: + all_events |= recorder.event_type + sys.monitoring.set_events(tool, all_events) + for recorder in recorders: + sys.monitoring.register_callback(tool, recorder.event_type, recorder(event_list)) + func() + sys.monitoring.set_events(tool, 0) + for recorder in recorders: + sys.monitoring.register_callback(tool, recorder.event_type, None) + for line in must_include: + self.assertIn(line, event_list) + finally: + sys.monitoring.set_events(tool, 0) + for recorder in recorders: + sys.monitoring.register_callback(tool, recorder.event_type, None) + + @staticmethod + def func1(): + line1 = 1 + + MUST_INCLUDE_LI = [ + ('instruction', 'func1', 2), + ('line', 'func1', 1), + ('instruction', 'func1', 4), + ('instruction', 'func1', 6)] + + def test_line_then_instruction(self): + recorders = [ LineRecorder, InstructionRecorder ] + self.check_events(self.func1, + recorders = recorders, must_include = self.EXPECTED_LI) + + def test_instruction_then_line(self): + recorders = [ InstructionRecorder, LineRecorderLowNoise ] + self.check_events(self.func1, + recorders = recorders, must_include = self.EXPECTED_LI) + + @staticmethod + def func2(): + len(()) + + MUST_INCLUDE_CI = [ + ('instruction', 'func2', 2), + ('call', 'func2', sys.monitoring.MISSING), + ('call', 'len', ()), + ('instruction', 'func2', 12), + ('instruction', 'func2', 14)] + + + + def test_line_then_instruction(self): + recorders = [ CallRecorder, InstructionRecorder ] + self.check_events(self.func2, + recorders = recorders, must_include = self.MUST_INCLUDE_CI) + + def test_instruction_then_line(self): + recorders = [ InstructionRecorder, CallRecorder ] + self.check_events(self.func2, + recorders = recorders, must_include = self.MUST_INCLUDE_CI) + +class TestLocalEvents(MonitoringTestBase, unittest.TestCase): + + def check_events(self, func, expected, tool=TEST_TOOL, recorders=(ExceptionRecorder,)): + try: + self.assertEqual(sys.monitoring._all_events(), {}) + event_list = [] + all_events = 0 + for recorder in recorders: + ev = recorder.event_type + sys.monitoring.register_callback(tool, ev, recorder(event_list)) + all_events |= ev + sys.monitoring.set_local_events(tool, func.__code__, all_events) + func() + sys.monitoring.set_local_events(tool, func.__code__, 0) + for recorder in recorders: + sys.monitoring.register_callback(tool, recorder.event_type, None) + self.assertEqual(event_list, expected) + finally: + sys.monitoring.set_local_events(tool, func.__code__, 0) + for recorder in recorders: + sys.monitoring.register_callback(tool, recorder.event_type, None) + + + def test_simple(self): + + def func1(): + line1 = 1 + line2 = 2 + line3 = 3 + + self.check_events(func1, recorders = MANY_RECORDERS, expected = [ + ('line', 'func1', 1), + ('line', 'func1', 2), + ('line', 'func1', 3)]) + + def test_c_call(self): + + def func2(): + line1 = 1 + [].append(2) + line3 = 3 + + self.check_events(func2, recorders = MANY_RECORDERS, expected = [ + ('line', 'func2', 1), + ('line', 'func2', 2), + ('call', 'append', [2]), + ('C return', 'append', [2]), + ('line', 'func2', 3)]) + + def test_try_except(self): + + def func3(): + try: + line = 2 + raise KeyError + except: + line = 5 + line = 6 + + self.check_events(func3, recorders = MANY_RECORDERS, expected = [ + ('line', 'func3', 1), + ('line', 'func3', 2), + ('line', 'func3', 3), + ('raise', KeyError), + ('line', 'func3', 4), + ('line', 'func3', 5), + ('line', 'func3', 6)]) + + +class TestSetGetEvents(MonitoringTestBase, unittest.TestCase): + + def test_global(self): + sys.monitoring.set_events(TEST_TOOL, E.PY_START) + self.assertEqual(sys.monitoring.get_events(TEST_TOOL), E.PY_START) + sys.monitoring.set_events(TEST_TOOL2, E.PY_START) + self.assertEqual(sys.monitoring.get_events(TEST_TOOL2), E.PY_START) + sys.monitoring.set_events(TEST_TOOL, 0) + self.assertEqual(sys.monitoring.get_events(TEST_TOOL), 0) + sys.monitoring.set_events(TEST_TOOL2,0) + self.assertEqual(sys.monitoring.get_events(TEST_TOOL2), 0) + + def test_local(self): + code = f1.__code__ + sys.monitoring.set_local_events(TEST_TOOL, code, E.PY_START) + self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), E.PY_START) + sys.monitoring.set_local_events(TEST_TOOL2, code, E.PY_START) + self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL2, code), E.PY_START) + sys.monitoring.set_local_events(TEST_TOOL, code, 0) + self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), 0) + sys.monitoring.set_local_events(TEST_TOOL2, code, 0) + self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL2, code), 0) + +class TestUninitialized(unittest.TestCase, MonitoringTestBase): + + @staticmethod + def f(): + pass + + def test_get_local_events_uninitialized(self): + self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, self.f.__code__), 0) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 890ffbf472c3..1aebe1b111f2 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1445,7 +1445,7 @@ class C(object): pass def func(): return sys._getframe() x = func() - check(x, size('3Pi3c7P2ic??2P')) + check(x, size('3Pii3c7P2ic??2P')) # function def func(): pass check(func, size('14Pi')) diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index 4907c930e143..980321e169b9 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -2808,5 +2808,65 @@ def foo(*args): sys.settrace(sys.gettrace()) +class TestLinesAfterTraceStarted(TraceTestCase): + + def test_events(self): + tracer = Tracer() + sys._getframe().f_trace = tracer.trace + sys.settrace(tracer.trace) + line = 4 + line = 5 + sys.settrace(None) + self.compare_events( + TestLinesAfterTraceStarted.test_events.__code__.co_firstlineno, + tracer.events, [ + (4, 'line'), + (5, 'line'), + (6, 'line')]) + + +class TestSetLocalTrace(TraceTestCase): + + def test_with_branches(self): + + def tracefunc(frame, event, arg): + if frame.f_code.co_name == "func": + frame.f_trace = tracefunc + line = frame.f_lineno - frame.f_code.co_firstlineno + events.append((line, event)) + return tracefunc + + def func(arg = 1): + N = 1 + if arg >= 2: + not_reached = 3 + else: + reached = 5 + if arg >= 3: + not_reached = 7 + else: + reached = 9 + the_end = 10 + + EXPECTED_EVENTS = [ + (0, 'call'), + (1, 'line'), + (2, 'line'), + (5, 'line'), + (6, 'line'), + (9, 'line'), + (10, 'line'), + (10, 'return'), + ] + + events = [] + sys.settrace(tracefunc) + sys._getframe().f_trace = tracefunc + func() + self.assertEqual(events, EXPECTED_EVENTS) + sys.settrace(None) + + + if __name__ == "__main__": unittest.main() diff --git a/Makefile.pre.in b/Makefile.pre.in index dc22683361d4..afd503ef1263 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -395,7 +395,9 @@ PYTHON_OBJS= \ Python/import.o \ Python/importdl.o \ Python/initconfig.o \ + Python/instrumentation.o \ Python/intrinsics.o \ + Python/legacy_tracing.o \ Python/marshal.o \ Python/modsupport.o \ Python/mysnprintf.o \ diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-31-17-24-03.gh-issue-103082.isRUcV.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-31-17-24-03.gh-issue-103082.isRUcV.rst new file mode 100644 index 000000000000..631ef4c78904 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-31-17-24-03.gh-issue-103082.isRUcV.rst @@ -0,0 +1 @@ +Implement :pep:`669` Low Impact Monitoring for CPython. diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 755d0b85e7cf..9b54c6105811 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -431,13 +431,13 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con) if (_Py_next_func_version != 0) { _Py_next_func_version++; } + co->_co_monitoring = NULL; + co->_co_instrumentation_version = 0; /* not set */ co->co_weakreflist = NULL; co->co_extra = NULL; co->_co_cached = NULL; - co->_co_linearray_entry_size = 0; - co->_co_linearray = NULL; memcpy(_PyCode_CODE(co), PyBytes_AS_STRING(con->code), PyBytes_GET_SIZE(con->code)); int entry_point = 0; @@ -816,54 +816,6 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno) * source location tracking (co_lines/co_positions) ******************/ -/* Use co_linetable to compute the line number from a bytecode index, addrq. See - lnotab_notes.txt for the details of the lnotab representation. -*/ - -int -_PyCode_CreateLineArray(PyCodeObject *co) -{ - assert(co->_co_linearray == NULL); - PyCodeAddressRange bounds; - int size; - int max_line = 0; - _PyCode_InitAddressRange(co, &bounds); - while(_PyLineTable_NextAddressRange(&bounds)) { - if (bounds.ar_line > max_line) { - max_line = bounds.ar_line; - } - } - if (max_line < (1 << 15)) { - size = 2; - } - else { - size = 4; - } - co->_co_linearray = PyMem_Malloc(Py_SIZE(co)*size); - if (co->_co_linearray == NULL) { - PyErr_NoMemory(); - return -1; - } - co->_co_linearray_entry_size = size; - _PyCode_InitAddressRange(co, &bounds); - while(_PyLineTable_NextAddressRange(&bounds)) { - int start = bounds.ar_start / sizeof(_Py_CODEUNIT); - int end = bounds.ar_end / sizeof(_Py_CODEUNIT); - for (int index = start; index < end; index++) { - assert(index < (int)Py_SIZE(co)); - if (size == 2) { - assert(((int16_t)bounds.ar_line) == bounds.ar_line); - ((int16_t *)co->_co_linearray)[index] = bounds.ar_line; - } - else { - assert(size == 4); - ((int32_t *)co->_co_linearray)[index] = bounds.ar_line; - } - } - } - return 0; -} - int PyCode_Addr2Line(PyCodeObject *co, int addrq) { @@ -871,9 +823,6 @@ PyCode_Addr2Line(PyCodeObject *co, int addrq) return co->co_firstlineno; } assert(addrq >= 0 && addrq < _PyCode_NBYTES(co)); - if (co->_co_linearray) { - return _PyCode_LineNumberFromArray(co, addrq / sizeof(_Py_CODEUNIT)); - } PyCodeAddressRange bounds; _PyCode_InitAddressRange(co, &bounds); return _PyCode_CheckLineNumber(addrq, &bounds); @@ -1531,17 +1480,17 @@ PyCode_GetFreevars(PyCodeObject *code) } static void -deopt_code(_Py_CODEUNIT *instructions, Py_ssize_t len) +deopt_code(PyCodeObject *code, _Py_CODEUNIT *instructions) { + Py_ssize_t len = Py_SIZE(code); for (int i = 0; i < len; i++) { - _Py_CODEUNIT instruction = instructions[i]; - int opcode = _PyOpcode_Deopt[instruction.op.code]; + int opcode = _Py_GetBaseOpcode(code, i); int caches = _PyOpcode_Caches[opcode]; instructions[i].op.code = opcode; - while (caches--) { - instructions[++i].op.code = CACHE; - instructions[i].op.arg = 0; + for (int j = 1; j <= caches; j++) { + instructions[i+j].cache = 0; } + i += caches; } } @@ -1559,7 +1508,7 @@ _PyCode_GetCode(PyCodeObject *co) if (code == NULL) { return NULL; } - deopt_code((_Py_CODEUNIT *)PyBytes_AS_STRING(code), Py_SIZE(co)); + deopt_code(co, (_Py_CODEUNIT *)PyBytes_AS_STRING(code)); assert(co->_co_cached->_co_code == NULL); co->_co_cached->_co_code = Py_NewRef(code); return code; @@ -1693,6 +1642,30 @@ code_new_impl(PyTypeObject *type, int argcount, int posonlyargcount, return co; } +static void +free_monitoring_data(_PyCoMonitoringData *data) +{ + if (data == NULL) { + return; + } + if (data->tools) { + PyMem_Free(data->tools); + } + if (data->lines) { + PyMem_Free(data->lines); + } + if (data->line_tools) { + PyMem_Free(data->line_tools); + } + if (data->per_instruction_opcodes) { + PyMem_Free(data->per_instruction_opcodes); + } + if (data->per_instruction_tools) { + PyMem_Free(data->per_instruction_tools); + } + PyMem_Free(data); +} + static void code_dealloc(PyCodeObject *co) { @@ -1739,9 +1712,7 @@ code_dealloc(PyCodeObject *co) if (co->co_weakreflist != NULL) { PyObject_ClearWeakRefs((PyObject*)co); } - if (co->_co_linearray) { - PyMem_Free(co->_co_linearray); - } + free_monitoring_data(co->_co_monitoring); PyObject_Free(co); } @@ -1885,7 +1856,7 @@ code_hash(PyCodeObject *co) SCRAMBLE_IN(co->co_firstlineno); SCRAMBLE_IN(Py_SIZE(co)); for (int i = 0; i < Py_SIZE(co); i++) { - int deop = _PyOpcode_Deopt[_PyCode_CODE(co)[i].op.code]; + int deop = _Py_GetBaseOpcode(co, i); SCRAMBLE_IN(deop); SCRAMBLE_IN(_PyCode_CODE(co)[i].op.arg); i += _PyOpcode_Caches[deop]; @@ -2314,7 +2285,7 @@ _PyCode_ConstantKey(PyObject *op) void _PyStaticCode_Fini(PyCodeObject *co) { - deopt_code(_PyCode_CODE(co), Py_SIZE(co)); + deopt_code(co, _PyCode_CODE(co)); PyMem_Free(co->co_extra); if (co->_co_cached != NULL) { Py_CLEAR(co->_co_cached->_co_code); @@ -2329,10 +2300,8 @@ _PyStaticCode_Fini(PyCodeObject *co) PyObject_ClearWeakRefs((PyObject *)co); co->co_weakreflist = NULL; } - if (co->_co_linearray) { - PyMem_Free(co->_co_linearray); - co->_co_linearray = NULL; - } + free_monitoring_data(co->_co_monitoring); + co->_co_monitoring = NULL; } int diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 63590d58809e..ef0070199ab2 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -17,7 +17,6 @@ static PyMemberDef frame_memberlist[] = { {"f_trace_lines", T_BOOL, OFF(f_trace_lines), 0}, - {"f_trace_opcodes", T_BOOL, OFF(f_trace_opcodes), 0}, {NULL} /* Sentinel */ }; @@ -104,24 +103,29 @@ frame_getback(PyFrameObject *f, void *closure) return res; } -// Given the index of the effective opcode, scan back to construct the oparg -// with EXTENDED_ARG. This only works correctly with *unquickened* code, -// obtained via a call to _PyCode_GetCode! -static unsigned int -get_arg(const _Py_CODEUNIT *codestr, Py_ssize_t i) +static PyObject * +frame_gettrace_opcodes(PyFrameObject *f, void *closure) { - _Py_CODEUNIT word; - unsigned int oparg = codestr[i].op.arg; - if (i >= 1 && (word = codestr[i-1]).op.code == EXTENDED_ARG) { - oparg |= word.op.arg << 8; - if (i >= 2 && (word = codestr[i-2]).op.code == EXTENDED_ARG) { - oparg |= word.op.arg << 16; - if (i >= 3 && (word = codestr[i-3]).op.code == EXTENDED_ARG) { - oparg |= word.op.arg << 24; - } - } + PyObject *result = f->f_trace_opcodes ? Py_True : Py_False; + return Py_NewRef(result); +} + +static int +frame_settrace_opcodes(PyFrameObject *f, PyObject* value, void *Py_UNUSED(ignored)) +{ + if (!PyBool_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "attribute value type must be bool"); + return -1; + } + if (value == Py_True) { + f->f_trace_opcodes = 1; + _PyInterpreterState_GET()->f_opcode_trace_set = true; } - return oparg; + else { + f->f_trace_opcodes = 0; + } + return 0; } /* Model the evaluation stack, to determine which jumps @@ -299,46 +303,52 @@ mark_stacks(PyCodeObject *code_obj, int len) while (todo) { todo = 0; /* Scan instructions */ - for (i = 0; i < len; i++) { + for (i = 0; i < len;) { int64_t next_stack = stacks[i]; + opcode = _Py_GetBaseOpcode(code_obj, i); + int oparg = 0; + while (opcode == EXTENDED_ARG) { + oparg = (oparg << 8) | code[i].op.arg; + i++; + opcode = _Py_GetBaseOpcode(code_obj, i); + stacks[i] = next_stack; + } + int next_i = i + _PyOpcode_Caches[opcode] + 1; if (next_stack == UNINITIALIZED) { + i = next_i; continue; } - opcode = code[i].op.code; + oparg = (oparg << 8) | code[i].op.arg; switch (opcode) { case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: { int64_t target_stack; - int j = get_arg(code, i); - j += i + 1; + int j = next_i + oparg; assert(j < len); - if (stacks[j] == UNINITIALIZED && j < i) { - todo = 1; - } next_stack = pop_value(next_stack); target_stack = next_stack; assert(stacks[j] == UNINITIALIZED || stacks[j] == target_stack); stacks[j] = target_stack; - stacks[i+1] = next_stack; + stacks[next_i] = next_stack; break; } case SEND: - j = get_arg(code, i) + i + INLINE_CACHE_ENTRIES_SEND + 1; + j = oparg + i + INLINE_CACHE_ENTRIES_SEND + 1; assert(j < len); assert(stacks[j] == UNINITIALIZED || stacks[j] == next_stack); stacks[j] = next_stack; - stacks[i+1] = next_stack; + stacks[next_i] = next_stack; break; case JUMP_FORWARD: - j = get_arg(code, i) + i + 1; + j = oparg + i + 1; assert(j < len); assert(stacks[j] == UNINITIALIZED || stacks[j] == next_stack); stacks[j] = next_stack; break; case JUMP_BACKWARD: case JUMP_BACKWARD_NO_INTERRUPT: - j = i + 1 - get_arg(code, i); + j = i + 1 - oparg; assert(j >= 0); assert(j < len); if (stacks[j] == UNINITIALIZED && j < i) { @@ -350,13 +360,13 @@ mark_stacks(PyCodeObject *code_obj, int len) case GET_ITER: case GET_AITER: next_stack = push_value(pop_value(next_stack), Iterator); - stacks[i+1] = next_stack; + stacks[next_i] = next_stack; break; case FOR_ITER: { int64_t target_stack = push_value(next_stack, Object); - stacks[i+1] = target_stack; - j = get_arg(code, i) + 1 + INLINE_CACHE_ENTRIES_FOR_ITER + i; + stacks[next_i] = target_stack; + j = oparg + 1 + INLINE_CACHE_ENTRIES_FOR_ITER + i; assert(j < len); assert(stacks[j] == UNINITIALIZED || stacks[j] == target_stack); stacks[j] = target_stack; @@ -364,16 +374,16 @@ mark_stacks(PyCodeObject *code_obj, int len) } case END_ASYNC_FOR: next_stack = pop_value(pop_value(next_stack)); - stacks[i+1] = next_stack; + stacks[next_i] = next_stack; break; case PUSH_EXC_INFO: next_stack = push_value(next_stack, Except); - stacks[i+1] = next_stack; + stacks[next_i] = next_stack; break; case POP_EXCEPT: assert(top_of_stack(next_stack) == Except); next_stack = pop_value(next_stack); - stacks[i+1] = next_stack; + stacks[next_i] = next_stack; break; case RETURN_VALUE: assert(pop_value(next_stack) == EMPTY_STACK); @@ -389,57 +399,62 @@ mark_stacks(PyCodeObject *code_obj, int len) break; case PUSH_NULL: next_stack = push_value(next_stack, Null); - stacks[i+1] = next_stack; + stacks[next_i] = next_stack; break; case LOAD_GLOBAL: { - int j = get_arg(code, i); + int j = oparg; if (j & 1) { next_stack = push_value(next_stack, Null); } next_stack = push_value(next_stack, Object); - stacks[i+1] = next_stack; + stacks[next_i] = next_stack; break; } case LOAD_ATTR: { assert(top_of_stack(next_stack) == Object); - int j = get_arg(code, i); + int j = oparg; if (j & 1) { next_stack = pop_value(next_stack); next_stack = push_value(next_stack, Null); next_stack = push_value(next_stack, Object); } - stacks[i+1] = next_stack; + stacks[next_i] = next_stack; break; } case CALL: { - int args = get_arg(code, i); + int args = oparg; for (int j = 0; j < args+2; j++) { next_stack = pop_value(next_stack); } next_stack = push_value(next_stack, Object); - stacks[i+1] = next_stack; + stacks[next_i] = next_stack; break; } case SWAP: { - int n = get_arg(code, i); + int n = oparg; next_stack = stack_swap(next_stack, n); - stacks[i+1] = next_stack; + stacks[next_i] = next_stack; break; } case COPY: { - int n = get_arg(code, i); + int n = oparg; next_stack = push_value(next_stack, peek(next_stack, n)); - stacks[i+1] = next_stack; + stacks[next_i] = next_stack; break; } + case CACHE: + case RESERVED: + { + assert(0); + } default: { - int delta = PyCompile_OpcodeStackEffect(opcode, get_arg(code, i)); + int delta = PyCompile_OpcodeStackEffect(opcode, oparg); assert(delta != PY_INVALID_STACK_EFFECT); while (delta < 0) { next_stack = pop_value(next_stack); @@ -449,9 +464,10 @@ mark_stacks(PyCodeObject *code_obj, int len) next_stack = push_value(next_stack, Object); delta--; } - stacks[i+1] = next_stack; + stacks[next_i] = next_stack; } } + i = next_i; } /* Scan exception table */ unsigned char *start = (unsigned char *)PyBytes_AS_STRING(code_obj->co_exceptiontable); @@ -646,31 +662,43 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore * In addition, jumps are forbidden when not tracing, * as this is a debugging feature. */ - switch(PyThreadState_GET()->tracing_what) { - case PyTrace_EXCEPTION: - PyErr_SetString(PyExc_ValueError, - "can only jump from a 'line' trace event"); - return -1; - case PyTrace_CALL: + int what_event = PyThreadState_GET()->what_event; + if (what_event < 0) { + PyErr_Format(PyExc_ValueError, + "f_lineno can only be set in a trace function"); + return -1; + } + switch (what_event) { + case PY_MONITORING_EVENT_PY_RESUME: + case PY_MONITORING_EVENT_JUMP: + case PY_MONITORING_EVENT_BRANCH: + case PY_MONITORING_EVENT_LINE: + case PY_MONITORING_EVENT_PY_YIELD: + /* Setting f_lineno is allowed for the above events */ + break; + case PY_MONITORING_EVENT_PY_START: PyErr_Format(PyExc_ValueError, "can't jump from the 'call' trace event of a new frame"); return -1; - case PyTrace_LINE: - break; - case PyTrace_RETURN: - if (state == FRAME_SUSPENDED) { - break; - } - /* fall through */ - default: + case PY_MONITORING_EVENT_CALL: + case PY_MONITORING_EVENT_C_RETURN: PyErr_SetString(PyExc_ValueError, + "can't jump during a call"); + return -1; + case PY_MONITORING_EVENT_PY_RETURN: + case PY_MONITORING_EVENT_PY_UNWIND: + case PY_MONITORING_EVENT_PY_THROW: + case PY_MONITORING_EVENT_RAISE: + case PY_MONITORING_EVENT_C_RAISE: + case PY_MONITORING_EVENT_INSTRUCTION: + case PY_MONITORING_EVENT_EXCEPTION_HANDLED: + PyErr_Format(PyExc_ValueError, "can only jump from a 'line' trace event"); return -1; - } - if (!f->f_trace) { - PyErr_Format(PyExc_ValueError, - "f_lineno can only be set by a trace function"); - return -1; + default: + PyErr_SetString(PyExc_SystemError, + "unexpected event type"); + return -1; } int new_lineno; @@ -803,6 +831,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore start_stack = pop_value(start_stack); } /* Finally set the new lasti and return OK. */ + f->f_last_traced_line = new_lineno; f->f_lineno = 0; f->f_frame->prev_instr = _PyCode_CODE(f->f_frame->f_code) + best_addr; return 0; @@ -823,7 +852,10 @@ frame_settrace(PyFrameObject *f, PyObject* v, void *closure) if (v == Py_None) { v = NULL; } - Py_XSETREF(f->f_trace, Py_XNewRef(v)); + if (v != f->f_trace) { + Py_XSETREF(f->f_trace, Py_XNewRef(v)); + f->f_last_traced_line = -1; + } return 0; } @@ -838,6 +870,7 @@ static PyGetSetDef frame_getsetlist[] = { {"f_globals", (getter)frame_getglobals, NULL, NULL}, {"f_builtins", (getter)frame_getbuiltins, NULL, NULL}, {"f_code", (getter)frame_getcode, NULL, NULL}, + {"f_trace_opcodes", (getter)frame_gettrace_opcodes, (setter)frame_settrace_opcodes, NULL}, {0} }; @@ -1023,6 +1056,7 @@ _PyFrame_New_NoTrack(PyCodeObject *code) f->f_trace_opcodes = 0; f->f_fast_as_locals = 0; f->f_lineno = 0; + f->f_last_traced_line = -1; return f; } diff --git a/Objects/object.c b/Objects/object.c index 71f098eed37f..56747fa193e1 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1972,6 +1972,7 @@ extern PyTypeObject _Py_GenericAliasIterType; extern PyTypeObject _PyMemoryIter_Type; extern PyTypeObject _PyLineIterator; extern PyTypeObject _PyPositionsIterator; +extern PyTypeObject _PyLegacyEventHandler_Type; static PyTypeObject* static_types[] = { // The two most important base types: must be initialized first and @@ -2069,6 +2070,7 @@ static PyTypeObject* static_types[] = { &_PyHamt_BitmapNode_Type, &_PyHamt_CollisionNode_Type, &_PyHamt_Type, + &_PyLegacyEventHandler_Type, &_PyInterpreterID_Type, &_PyLineIterator, &_PyManagedBuffer_Type, diff --git a/PCbuild/_freeze_module.vcxproj b/PCbuild/_freeze_module.vcxproj index 70ca0787cfd6..d897925f58c0 100644 --- a/PCbuild/_freeze_module.vcxproj +++ b/PCbuild/_freeze_module.vcxproj @@ -209,6 +209,8 @@ + + diff --git a/PCbuild/_freeze_module.vcxproj.filters b/PCbuild/_freeze_module.vcxproj.filters index 464cbec62a62..176935a63c48 100644 --- a/PCbuild/_freeze_module.vcxproj.filters +++ b/PCbuild/_freeze_module.vcxproj.filters @@ -214,6 +214,12 @@ Source Files + + Source Files + + + Source Files + Source Files diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index a465f99eca82..8aafcb786a60 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -532,6 +532,8 @@ + + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 52cd4bbb6fb1..07476f308333 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -1178,6 +1178,12 @@ Source Files + + Source Files + + + Source Files + Python diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 72f85cc92b0c..5c6398aba198 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -14,6 +14,7 @@ #include "pycore_function.h" #include "pycore_intrinsics.h" #include "pycore_long.h" // _PyLong_GetZero() +#include "pycore_instruments.h" #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_moduleobject.h" // PyModuleObject #include "pycore_opcode.h" // EXTRA_CASES @@ -134,11 +135,45 @@ dummy_func( inst(RESUME, (--)) { assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); - if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { + /* Possibly combine this with eval breaker */ + if (frame->f_code->_co_instrumentation_version != tstate->interp->monitoring_version) { + int err = _Py_Instrument(frame->f_code, tstate->interp); + ERROR_IF(err, error); + next_instr--; + } + else if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { goto handle_eval_breaker; } } + inst(INSTRUMENTED_RESUME, (--)) { + /* Possible performance enhancement: + * We need to check the eval breaker anyway, can we + * combine the instrument verison check and the eval breaker test? + */ + if (frame->f_code->_co_instrumentation_version != tstate->interp->monitoring_version) { + if (_Py_Instrument(frame->f_code, tstate->interp)) { + goto error; + } + next_instr--; + } + else { + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_call_instrumentation( + tstate, oparg > 0, frame, next_instr-1); + stack_pointer = _PyFrame_GetStackPointer(frame); + ERROR_IF(err, error); + if (frame->prev_instr != next_instr-1) { + /* Instrumentation has jumped */ + next_instr = frame->prev_instr; + DISPATCH(); + } + if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { + goto handle_eval_breaker; + } + } + } + inst(LOAD_CLOSURE, (-- value)) { /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ value = GETLOCAL(oparg); @@ -183,6 +218,34 @@ dummy_func( macro(END_FOR) = POP_TOP + POP_TOP; + inst(INSTRUMENTED_END_FOR, (receiver, value --)) { + /* Need to create a fake StopIteration error here, + * to conform to PEP 380 */ + if (PyGen_Check(receiver)) { + PyErr_SetObject(PyExc_StopIteration, value); + if (monitor_stop_iteration(tstate, frame, next_instr-1)) { + goto error; + } + PyErr_SetRaisedException(NULL); + } + DECREF_INPUTS(); + } + + inst(END_SEND, (receiver, value -- value)) { + Py_DECREF(receiver); + } + + inst(INSTRUMENTED_END_SEND, (receiver, value -- value)) { + if (PyGen_Check(receiver) || PyCoro_CheckExact(receiver)) { + PyErr_SetObject(PyExc_StopIteration, value); + if (monitor_stop_iteration(tstate, frame, next_instr-1)) { + goto error; + } + PyErr_SetRaisedException(NULL); + } + Py_DECREF(receiver); + } + inst(UNARY_NEGATIVE, (value -- res)) { res = PyNumber_Negative(value); DECREF_INPUTS(); @@ -222,7 +285,6 @@ dummy_func( inst(BINARY_OP_MULTIPLY_INT, (unused/1, left, right -- prod)) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -233,7 +295,6 @@ dummy_func( } inst(BINARY_OP_MULTIPLY_FLOAT, (unused/1, left, right -- prod)) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -243,7 +304,6 @@ dummy_func( } inst(BINARY_OP_SUBTRACT_INT, (unused/1, left, right -- sub)) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -254,7 +314,6 @@ dummy_func( } inst(BINARY_OP_SUBTRACT_FLOAT, (unused/1, left, right -- sub)) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -263,7 +322,6 @@ dummy_func( } inst(BINARY_OP_ADD_UNICODE, (unused/1, left, right -- res)) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -280,7 +338,6 @@ dummy_func( // specializations, but there is no output. // At the end we just skip over the STORE_FAST. inst(BINARY_OP_INPLACE_ADD_UNICODE, (left, right --)) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP]; @@ -310,7 +367,6 @@ dummy_func( } inst(BINARY_OP_ADD_FLOAT, (unused/1, left, right -- sum)) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -320,7 +376,6 @@ dummy_func( } inst(BINARY_OP_ADD_INT, (unused/1, left, right -- sum)) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -342,7 +397,6 @@ dummy_func( #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); next_instr--; _Py_Specialize_BinarySubscr(container, sub, next_instr); DISPATCH_SAME_OPARG(); @@ -386,7 +440,6 @@ dummy_func( } inst(BINARY_SUBSCR_LIST_INT, (unused/1, list, sub -- res)) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -403,7 +456,6 @@ dummy_func( } inst(BINARY_SUBSCR_TUPLE_INT, (unused/1, tuple, sub -- res)) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -420,7 +472,6 @@ dummy_func( } inst(BINARY_SUBSCR_DICT, (unused/1, dict, sub -- res)) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); @@ -479,7 +530,6 @@ dummy_func( inst(STORE_SUBSCR, (counter/1, v, container, sub -- )) { #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { - assert(cframe.use_tracing == 0); next_instr--; _Py_Specialize_StoreSubscr(container, sub, next_instr); DISPATCH_SAME_OPARG(); @@ -497,7 +547,6 @@ dummy_func( } inst(STORE_SUBSCR_LIST_INT, (unused/1, value, list, sub -- )) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -517,7 +566,6 @@ dummy_func( } inst(STORE_SUBSCR_DICT, (unused/1, value, dict, sub -- )) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); @@ -573,7 +621,6 @@ dummy_func( assert(EMPTY()); /* Restore previous cframe and return. */ tstate->cframe = cframe.previous; - tstate->cframe->use_tracing = cframe.use_tracing; assert(tstate->cframe->current_frame == frame->previous); assert(!_PyErr_Occurred(tstate)); _Py_LeaveRecursiveCallTstate(tstate); @@ -584,8 +631,24 @@ dummy_func( STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); - TRACE_FUNCTION_EXIT(); - DTRACE_FUNCTION_EXIT(); + _Py_LeaveRecursiveCallPy(tstate); + assert(frame != &entry_frame); + // GH-99729: We need to unlink the frame *before* clearing it: + _PyInterpreterFrame *dying = frame; + frame = cframe.current_frame = dying->previous; + _PyEvalFrameClearAndPop(tstate, dying); + _PyFrame_StackPush(frame, retval); + goto resume_frame; + } + + inst(INSTRUMENTED_RETURN_VALUE, (retval --)) { + int err = _Py_call_instrumentation_arg( + tstate, PY_MONITORING_EVENT_PY_RETURN, + frame, next_instr-1, retval); + if (err) goto error; + STACK_SHRINK(1); + assert(EMPTY()); + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_LeaveRecursiveCallPy(tstate); assert(frame != &entry_frame); // GH-99729: We need to unlink the frame *before* clearing it: @@ -601,8 +664,25 @@ dummy_func( Py_INCREF(retval); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); - TRACE_FUNCTION_EXIT(); - DTRACE_FUNCTION_EXIT(); + _Py_LeaveRecursiveCallPy(tstate); + assert(frame != &entry_frame); + // GH-99729: We need to unlink the frame *before* clearing it: + _PyInterpreterFrame *dying = frame; + frame = cframe.current_frame = dying->previous; + _PyEvalFrameClearAndPop(tstate, dying); + _PyFrame_StackPush(frame, retval); + goto resume_frame; + } + + inst(INSTRUMENTED_RETURN_CONST, (--)) { + PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); + int err = _Py_call_instrumentation_arg( + tstate, PY_MONITORING_EVENT_PY_RETURN, + frame, next_instr-1, retval); + if (err) goto error; + Py_INCREF(retval); + assert(EMPTY()); + _PyFrame_SetStackPointer(frame, stack_pointer); _Py_LeaveRecursiveCallPy(tstate); assert(frame != &entry_frame); // GH-99729: We need to unlink the frame *before* clearing it: @@ -730,7 +810,6 @@ dummy_func( #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); next_instr--; _Py_Specialize_Send(receiver, next_instr); DISPATCH_SAME_OPARG(); @@ -739,6 +818,20 @@ dummy_func( DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ assert(frame != &entry_frame); + if ((Py_TYPE(receiver) == &PyGen_Type || + Py_TYPE(receiver) == &PyCoro_Type) && ((PyGenObject *)receiver)->gi_frame_state < FRAME_EXECUTING) + { + PyGenObject *gen = (PyGenObject *)receiver; + _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; + frame->yield_offset = oparg; + STACK_SHRINK(1); + _PyFrame_StackPush(gen_frame, v); + gen->gi_frame_state = FRAME_EXECUTING; + gen->gi_exc_state.previous_item = tstate->exc_info; + tstate->exc_info = &gen->gi_exc_state; + JUMPBY(INLINE_CACHE_ENTRIES_SEND + oparg); + DISPATCH_INLINED(gen_frame); + } if (Py_IsNone(v) && PyIter_Check(receiver)) { retval = Py_TYPE(receiver)->tp_iternext(receiver); } @@ -746,26 +839,22 @@ dummy_func( retval = PyObject_CallMethodOneArg(receiver, &_Py_ID(send), v); } if (retval == NULL) { - if (tstate->c_tracefunc != NULL - && _PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) - call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame); + if (_PyErr_ExceptionMatches(tstate, PyExc_StopIteration) + ) { + monitor_raise(tstate, frame, next_instr-1); + } if (_PyGen_FetchStopIterationValue(&retval) == 0) { assert(retval != NULL); JUMPBY(oparg); } else { - assert(retval == NULL); goto error; } } - else { - assert(retval != NULL); - } Py_DECREF(v); } inst(SEND_GEN, (unused/1, receiver, v -- receiver)) { - assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type, SEND); @@ -782,6 +871,26 @@ dummy_func( DISPATCH_INLINED(gen_frame); } + inst(INSTRUMENTED_YIELD_VALUE, (retval -- unused)) { + assert(frame != &entry_frame); + PyGenObject *gen = _PyFrame_GetGenerator(frame); + gen->gi_frame_state = FRAME_SUSPENDED; + _PyFrame_SetStackPointer(frame, stack_pointer - 1); + int err = _Py_call_instrumentation_arg( + tstate, PY_MONITORING_EVENT_PY_YIELD, + frame, next_instr-1, retval); + if (err) goto error; + tstate->exc_info = gen->gi_exc_state.previous_item; + gen->gi_exc_state.previous_item = NULL; + _Py_LeaveRecursiveCallPy(tstate); + _PyInterpreterFrame *gen_frame = frame; + frame = cframe.current_frame = frame->previous; + gen_frame->previous = NULL; + frame->prev_instr -= frame->yield_offset; + _PyFrame_StackPush(frame, retval); + goto resume_frame; + } + inst(YIELD_VALUE, (retval -- unused)) { // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() @@ -790,8 +899,6 @@ dummy_func( PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_SUSPENDED; _PyFrame_SetStackPointer(frame, stack_pointer - 1); - TRACE_FUNCTION_EXIT(); - DTRACE_FUNCTION_EXIT(); tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; _Py_LeaveRecursiveCallPy(tstate); @@ -930,7 +1037,6 @@ dummy_func( #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); next_instr--; _Py_Specialize_UnpackSequence(seq, next_instr, oparg); DISPATCH_SAME_OPARG(); @@ -994,7 +1100,6 @@ dummy_func( inst(STORE_ATTR, (counter/1, unused/3, v, owner --)) { #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { - assert(cframe.use_tracing == 0); PyObject *name = GETITEM(frame->f_code->co_names, oparg); next_instr--; _Py_Specialize_StoreAttr(owner, next_instr, name); @@ -1111,7 +1216,6 @@ dummy_func( #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); next_instr--; _Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name); @@ -1163,7 +1267,6 @@ dummy_func( } inst(LOAD_GLOBAL_MODULE, (unused/1, index/1, version/1, unused/1 -- null if (oparg & 1), res)) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -1177,11 +1280,11 @@ dummy_func( } inst(LOAD_GLOBAL_BUILTIN, (unused/1, index/1, mod_version/1, bltn_version/1 -- null if (oparg & 1), res)) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); PyDictObject *bdict = (PyDictObject *)BUILTINS(); + assert(opcode == LOAD_GLOBAL_BUILTIN); DEOPT_IF(mdict->ma_keys->dk_version != mod_version, LOAD_GLOBAL); DEOPT_IF(bdict->ma_keys->dk_version != bltn_version, LOAD_GLOBAL); assert(DK_IS_UNICODE(bdict->ma_keys)); @@ -1465,7 +1568,6 @@ dummy_func( #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); next_instr--; _Py_Specialize_LoadAttr(owner, next_instr, name); @@ -1511,7 +1613,6 @@ dummy_func( } inst(LOAD_ATTR_INSTANCE_VALUE, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { - assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -1528,7 +1629,6 @@ dummy_func( } inst(LOAD_ATTR_MODULE, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -1545,7 +1645,6 @@ dummy_func( } inst(LOAD_ATTR_WITH_HINT, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { - assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -1576,7 +1675,6 @@ dummy_func( } inst(LOAD_ATTR_SLOT, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { - assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -1590,7 +1688,6 @@ dummy_func( } inst(LOAD_ATTR_CLASS, (unused/1, type_version/2, unused/2, descr/4, cls -- res2 if (oparg & 1), res)) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -1606,7 +1703,6 @@ dummy_func( } inst(LOAD_ATTR_PROPERTY, (unused/1, type_version/2, func_version/2, fget/4, owner -- unused if (oparg & 1), unused)) { - assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -1632,7 +1728,6 @@ dummy_func( } inst(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, (unused/1, type_version/2, func_version/2, getattribute/4, owner -- unused if (oparg & 1), unused)) { - assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -1660,7 +1755,6 @@ dummy_func( } inst(STORE_ATTR_INSTANCE_VALUE, (unused/1, type_version/2, index/1, value, owner --)) { - assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -1681,7 +1775,6 @@ dummy_func( } inst(STORE_ATTR_WITH_HINT, (unused/1, type_version/2, hint/1, value, owner --)) { - assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -1723,7 +1816,6 @@ dummy_func( } inst(STORE_ATTR_SLOT, (unused/1, type_version/2, index/1, value, owner --)) { - assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -1746,7 +1838,6 @@ dummy_func( #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); next_instr--; _Py_Specialize_CompareOp(left, right, next_instr, oparg); DISPATCH_SAME_OPARG(); @@ -1761,7 +1852,6 @@ dummy_func( } inst(COMPARE_OP_FLOAT, (unused/1, left, right -- res)) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -1777,7 +1867,6 @@ dummy_func( // Similar to COMPARE_OP_FLOAT inst(COMPARE_OP_INT, (unused/1, left, right -- res)) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -1797,7 +1886,6 @@ dummy_func( // Similar to COMPARE_OP_FLOAT, but for ==, != only inst(COMPARE_OP_STR, (unused/1, left, right -- res)) { - assert(cframe.use_tracing == 0); DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2044,7 +2132,6 @@ dummy_func( #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); next_instr--; _Py_Specialize_ForIter(iter, next_instr, oparg); DISPATCH_SAME_OPARG(); @@ -2059,13 +2146,12 @@ dummy_func( if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { goto error; } - else if (tstate->c_tracefunc != NULL) { - call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame); - } + monitor_raise(tstate, frame, next_instr-1); _PyErr_Clear(tstate); } /* iterator ended normally */ - assert(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == END_FOR); + assert(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == END_FOR || + next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == INSTRUMENTED_END_FOR); Py_DECREF(iter); STACK_SHRINK(1); /* Jump forward oparg, then skip following END_FOR instruction */ @@ -2075,8 +2161,35 @@ dummy_func( // Common case: no jump, leave it to the code generator } + inst(INSTRUMENTED_FOR_ITER, ( -- )) { + _Py_CODEUNIT *here = next_instr-1; + _Py_CODEUNIT *target; + PyObject *iter = TOP(); + PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); + if (next != NULL) { + PUSH(next); + target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER; + } + else { + if (_PyErr_Occurred(tstate)) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { + goto error; + } + monitor_raise(tstate, frame, here); + _PyErr_Clear(tstate); + } + /* iterator ended normally */ + assert(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == END_FOR || + next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == INSTRUMENTED_END_FOR); + STACK_SHRINK(1); + Py_DECREF(iter); + /* Skip END_FOR */ + target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; + } + INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); + } + inst(FOR_ITER_LIST, (unused/1, iter -- iter, next)) { - assert(cframe.use_tracing == 0); DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -2099,7 +2212,6 @@ dummy_func( } inst(FOR_ITER_TUPLE, (unused/1, iter -- iter, next)) { - assert(cframe.use_tracing == 0); _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -2122,7 +2234,6 @@ dummy_func( } inst(FOR_ITER_RANGE, (unused/1, iter -- iter, next)) { - assert(cframe.use_tracing == 0); _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -2143,7 +2254,6 @@ dummy_func( } inst(FOR_ITER_GEN, (unused/1, iter -- iter, unused)) { - assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER); @@ -2155,7 +2265,8 @@ dummy_func( gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg); - assert(next_instr->op.code == END_FOR); + assert(next_instr->op.code == END_FOR || + next_instr->op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); } @@ -2264,7 +2375,6 @@ dummy_func( inst(LOAD_ATTR_METHOD_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, self -- res2 if (oparg & 1), res)) { /* Cached method object */ - assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2283,7 +2393,6 @@ dummy_func( } inst(LOAD_ATTR_METHOD_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (oparg & 1), res)) { - assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -2296,7 +2405,6 @@ dummy_func( } inst(LOAD_ATTR_METHOD_LAZY_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (oparg & 1), res)) { - assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -2318,6 +2426,21 @@ dummy_func( kwnames = GETITEM(frame->f_code->co_consts, oparg); } + inst(INSTRUMENTED_CALL, ( -- )) { + int is_meth = PEEK(oparg+2) != NULL; + int total_args = oparg + is_meth; + PyObject *function = PEEK(total_args + 1); + PyObject *arg = total_args == 0 ? + &_PyInstrumentation_MISSING : PEEK(total_args); + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_CALL, + frame, next_instr-1, function, arg); + ERROR_IF(err, error); + _PyCallCache *cache = (_PyCallCache *)next_instr; + INCREMENT_ADAPTIVE_COUNTER(cache->counter); + GO_TO_INSTRUCTION(CALL); + } + // Cache layout: counter/1, func_version/2 // Neither CALL_INTRINSIC_1/2 nor CALL_FUNCTION_EX are members! family(call, INLINE_CACHE_ENTRIES_CALL) = { @@ -2359,7 +2482,6 @@ dummy_func( #if ENABLE_SPECIALIZATION _PyCallCache *cache = (_PyCallCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); next_instr--; _Py_Specialize_Call(callable, next_instr, total_args, kwnames); DISPATCH_SAME_OPARG(); @@ -2402,16 +2524,26 @@ dummy_func( DISPATCH_INLINED(new_frame); } /* Callable is not a normal Python function */ - if (cframe.use_tracing) { - res = trace_call_function( - tstate, callable, args, - positional_args, kwnames); - } - else { - res = PyObject_Vectorcall( - callable, args, - positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, - kwnames); + res = PyObject_Vectorcall( + callable, args, + positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, + kwnames); + if (opcode == INSTRUMENTED_CALL) { + PyObject *arg = total_args == 0 ? + &_PyInstrumentation_MISSING : PEEK(total_args); + if (res == NULL) { + _Py_call_instrumentation_exc2( + tstate, PY_MONITORING_EVENT_C_RAISE, + frame, next_instr-1, callable, arg); + } + else { + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_C_RETURN, + frame, next_instr-1, callable, arg); + if (err < 0) { + Py_CLEAR(res); + } + } } kwnames = NULL; assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); @@ -2504,7 +2636,6 @@ dummy_func( inst(CALL_NO_KW_TYPE_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) { assert(kwnames == NULL); - assert(cframe.use_tracing == 0); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); PyObject *obj = args[0]; @@ -2517,7 +2648,6 @@ dummy_func( inst(CALL_NO_KW_STR_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) { assert(kwnames == NULL); - assert(cframe.use_tracing == 0); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL); @@ -2570,7 +2700,6 @@ dummy_func( } inst(CALL_NO_KW_BUILTIN_O, (unused/1, unused/2, method, callable, args[oparg] -- res)) { - assert(cframe.use_tracing == 0); /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -2602,7 +2731,6 @@ dummy_func( } inst(CALL_NO_KW_BUILTIN_FAST, (unused/1, unused/2, method, callable, args[oparg] -- res)) { - assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -2638,7 +2766,6 @@ dummy_func( } inst(CALL_BUILTIN_FAST_WITH_KEYWORDS, (unused/1, unused/2, method, callable, args[oparg] -- res)) { - assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -2674,7 +2801,6 @@ dummy_func( } inst(CALL_NO_KW_LEN, (unused/1, unused/2, method, callable, args[oparg] -- res)) { - assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -2702,7 +2828,6 @@ dummy_func( } inst(CALL_NO_KW_ISINSTANCE, (unused/1, unused/2, method, callable, args[oparg] -- res)) { - assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -2733,7 +2858,6 @@ dummy_func( // This is secretly a super-instruction inst(CALL_NO_KW_LIST_APPEND, (unused/1, unused/2, method, self, args[oparg] -- unused)) { - assert(cframe.use_tracing == 0); assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -2882,12 +3006,14 @@ dummy_func( CHECK_EVAL_BREAKER(); } + inst(INSTRUMENTED_CALL_FUNCTION_EX, ( -- )) { + GO_TO_INSTRUCTION(CALL_FUNCTION_EX); + } + inst(CALL_FUNCTION_EX, (unused, func, callargs, kwargs if (oparg & 1) -- result)) { - if (oparg & 1) { - // DICT_MERGE is called before this opcode if there are kwargs. - // It converts all dict subtypes in kwargs into regular dicts. - assert(PyDict_CheckExact(kwargs)); - } + // DICT_MERGE is called before this opcode if there are kwargs. + // It converts all dict subtypes in kwargs into regular dicts. + assert(kwargs == NULL || PyDict_CheckExact(kwargs)); if (!PyTuple_CheckExact(callargs)) { if (check_args_iterable(tstate, func, callargs) < 0) { goto error; @@ -2899,10 +3025,35 @@ dummy_func( Py_SETREF(callargs, tuple); } assert(PyTuple_CheckExact(callargs)); - - result = do_call_core(tstate, func, callargs, kwargs, cframe.use_tracing); + EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func); + if (opcode == INSTRUMENTED_CALL_FUNCTION_EX && + !PyFunction_Check(func) && !PyMethod_Check(func) + ) { + PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ? + PyTuple_GET_ITEM(callargs, 0) : Py_None; + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_CALL, + frame, next_instr-1, func, arg); + if (err) goto error; + result = PyObject_Call(func, callargs, kwargs); + if (result == NULL) { + _Py_call_instrumentation_exc2( + tstate, PY_MONITORING_EVENT_C_RAISE, + frame, next_instr-1, func, arg); + } + else { + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_C_RETURN, + frame, next_instr-1, func, arg); + if (err < 0) { + Py_CLEAR(result); + } + } + } + else { + result = PyObject_Call(func, callargs, kwargs); + } DECREF_INPUTS(); - assert(PEEK(3 + (oparg & 1)) == NULL); ERROR_IF(result == NULL, error); CHECK_EVAL_BREAKER(); @@ -3018,7 +3169,6 @@ dummy_func( #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); next_instr--; _Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, &GETLOCAL(0)); DISPATCH_SAME_OPARG(); @@ -3039,9 +3189,105 @@ dummy_func( assert(oparg >= 2); } - inst(EXTENDED_ARG, (--)) { + inst(INSTRUMENTED_LINE, ( -- )) { + _Py_CODEUNIT *here = next_instr-1; + _PyFrame_SetStackPointer(frame, stack_pointer); + int original_opcode = _Py_call_instrumentation_line( + tstate, frame, here); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (original_opcode < 0) { + next_instr = here+1; + goto error; + } + next_instr = frame->prev_instr; + if (next_instr != here) { + DISPATCH(); + } + if (_PyOpcode_Caches[original_opcode]) { + _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1); + INCREMENT_ADAPTIVE_COUNTER(cache->counter); + } + opcode = original_opcode; + DISPATCH_GOTO(); + } + + inst(INSTRUMENTED_INSTRUCTION, ( -- )) { + int next_opcode = _Py_call_instrumentation_instruction( + tstate, frame, next_instr-1); + ERROR_IF(next_opcode < 0, error); + next_instr--; + if (_PyOpcode_Caches[next_opcode]) { + _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1); + INCREMENT_ADAPTIVE_COUNTER(cache->counter); + } + assert(next_opcode > 0 && next_opcode < 256); + opcode = next_opcode; + DISPATCH_GOTO(); + } + + inst(INSTRUMENTED_JUMP_FORWARD, ( -- )) { + INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); + } + + inst(INSTRUMENTED_JUMP_BACKWARD, ( -- )) { + INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); + CHECK_EVAL_BREAKER(); + } + + inst(INSTRUMENTED_POP_JUMP_IF_TRUE, ( -- )) { + PyObject *cond = POP(); + int err = PyObject_IsTrue(cond); + Py_DECREF(cond); + ERROR_IF(err < 0, error); + _Py_CODEUNIT *here = next_instr-1; + assert(err == 0 || err == 1); + int offset = err*oparg; + INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); + } + + inst(INSTRUMENTED_POP_JUMP_IF_FALSE, ( -- )) { + PyObject *cond = POP(); + int err = PyObject_IsTrue(cond); + Py_DECREF(cond); + ERROR_IF(err < 0, error); + _Py_CODEUNIT *here = next_instr-1; + assert(err == 0 || err == 1); + int offset = (1-err)*oparg; + INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); + } + + inst(INSTRUMENTED_POP_JUMP_IF_NONE, ( -- )) { + PyObject *value = POP(); + _Py_CODEUNIT *here = next_instr-1; + int offset; + if (Py_IsNone(value)) { + _Py_DECREF_NO_DEALLOC(value); + offset = oparg; + } + else { + Py_DECREF(value); + offset = 0; + } + INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); + } + + inst(INSTRUMENTED_POP_JUMP_IF_NOT_NONE, ( -- )) { + PyObject *value = POP(); + _Py_CODEUNIT *here = next_instr-1; + int offset; + if (Py_IsNone(value)) { + _Py_DECREF_NO_DEALLOC(value); + offset = 0; + } + else { + Py_DECREF(value); + offset = oparg; + } + INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); + } + + inst(EXTENDED_ARG, ( -- )) { assert(oparg); - assert(cframe.use_tracing == 0); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); @@ -3049,6 +3295,12 @@ dummy_func( } inst(CACHE, (--)) { + assert(0 && "Executing a cache."); + Py_UNREACHABLE(); + } + + inst(RESERVED, (--)) { + assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); } diff --git a/Python/ceval.c b/Python/ceval.c index 7d60cf987e9c..a38c9ec9ad5f 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -10,6 +10,7 @@ #include "pycore_function.h" #include "pycore_intrinsics.h" #include "pycore_long.h" // _PyLong_GetZero() +#include "pycore_instruments.h" #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_moduleobject.h" // PyModuleObject #include "pycore_opcode.h" // EXTRA_CASES @@ -92,13 +93,6 @@ #define _Py_atomic_load_relaxed_int32(ATOMIC_VAL) _Py_atomic_load_relaxed(ATOMIC_VAL) #endif -/* Forward declarations */ -static PyObject *trace_call_function( - PyThreadState *tstate, PyObject *callable, PyObject **stack, - Py_ssize_t oparg, PyObject *kwnames); -static PyObject * do_call_core( - PyThreadState *tstate, PyObject *func, - PyObject *callargs, PyObject *kwdict, int use_tracing); #ifdef LLTRACE static void @@ -179,19 +173,22 @@ lltrace_resume_frame(_PyInterpreterFrame *frame) PyErr_SetRaisedException(exc); } #endif -static int call_trace(Py_tracefunc, PyObject *, - PyThreadState *, _PyInterpreterFrame *, - int, PyObject *); -static int call_trace_protected(Py_tracefunc, PyObject *, - PyThreadState *, _PyInterpreterFrame *, - int, PyObject *); -static void call_exc_trace(Py_tracefunc, PyObject *, - PyThreadState *, _PyInterpreterFrame *); -static int maybe_call_line_trace(Py_tracefunc, PyObject *, - PyThreadState *, _PyInterpreterFrame *, int); -static void maybe_dtrace_line(_PyInterpreterFrame *, PyTraceInfo *, int); -static void dtrace_function_entry(_PyInterpreterFrame *); -static void dtrace_function_return(_PyInterpreterFrame *); + +static void monitor_raise(PyThreadState *tstate, + _PyInterpreterFrame *frame, + _Py_CODEUNIT *instr); +static int monitor_stop_iteration(PyThreadState *tstate, + _PyInterpreterFrame *frame, + _Py_CODEUNIT *instr); +static void monitor_unwind(PyThreadState *tstate, + _PyInterpreterFrame *frame, + _Py_CODEUNIT *instr); +static void monitor_handled(PyThreadState *tstate, + _PyInterpreterFrame *frame, + _Py_CODEUNIT *instr, PyObject *exc); +static void monitor_throw(PyThreadState *tstate, + _PyInterpreterFrame *frame, + _Py_CODEUNIT *instr); static PyObject * import_name(PyThreadState *, _PyInterpreterFrame *, PyObject *, PyObject *, PyObject *); @@ -217,21 +214,6 @@ _PyEvalFrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame); "cannot access free variable '%s' where it is not associated with a" \ " value in enclosing scope" -#ifndef NDEBUG -/* Ensure that tstate is valid: sanity check for PyEval_AcquireThread() and - PyEval_RestoreThread(). Detect if tstate memory was freed. It can happen - when a thread continues to run after Python finalization, especially - daemon threads. */ -static int -is_tstate_valid(PyThreadState *tstate) -{ - assert(!_PyMem_IsPtrFreed(tstate)); - assert(!_PyMem_IsPtrFreed(tstate->interp)); - return 1; -} -#endif - - #ifdef HAVE_ERRNO_H #include #endif @@ -596,63 +578,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) #include "ceval_macros.h" -static int -trace_function_entry(PyThreadState *tstate, _PyInterpreterFrame *frame) -{ - if (tstate->c_tracefunc != NULL) { - /* tstate->c_tracefunc, if defined, is a - function that will be called on *every* entry - to a code block. Its return value, if not - None, is a function that will be called at - the start of each executed line of code. - (Actually, the function must return itself - in order to continue tracing.) The trace - functions are called with three arguments: - a pointer to the current frame, a string - indicating why the function is called, and - an argument which depends on the situation. - The global trace function is also called - whenever an exception is detected. */ - if (call_trace_protected(tstate->c_tracefunc, - tstate->c_traceobj, - tstate, frame, - PyTrace_CALL, Py_None)) { - /* Trace function raised an error */ - return -1; - } - } - if (tstate->c_profilefunc != NULL) { - /* Similar for c_profilefunc, except it needn't - return itself and isn't called for "line" events */ - if (call_trace_protected(tstate->c_profilefunc, - tstate->c_profileobj, - tstate, frame, - PyTrace_CALL, Py_None)) { - /* Profile function raised an error */ - return -1; - } - } - return 0; -} - -static int -trace_function_exit(PyThreadState *tstate, _PyInterpreterFrame *frame, PyObject *retval) -{ - if (tstate->c_tracefunc) { - if (call_trace_protected(tstate->c_tracefunc, tstate->c_traceobj, - tstate, frame, PyTrace_RETURN, retval)) { - return -1; - } - } - if (tstate->c_profilefunc) { - if (call_trace_protected(tstate->c_profilefunc, tstate->c_profileobj, - tstate, frame, PyTrace_RETURN, retval)) { - return -1; - } - } - return 0; -} - int _Py_CheckRecursiveCallPy( PyThreadState *tstate) @@ -730,7 +655,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int * strict stack discipline must be maintained. */ _PyCFrame *prev_cframe = tstate->cframe; - cframe.use_tracing = prev_cframe->use_tracing; cframe.previous = prev_cframe; tstate->cframe = &cframe; @@ -765,8 +689,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int if (_Py_EnterRecursivePy(tstate)) { goto exit_unwind; } - TRACE_FUNCTION_THROW_ENTRY(); - DTRACE_FUNCTION_ENTRY(); + /* Because this avoids the RESUME, + * we need to update instrumentation */ + _Py_Instrument(frame->f_code, tstate->interp); + monitor_throw(tstate, frame, frame->prev_instr); + /* TO DO -- Monitor throw entry. */ goto resume_with_error; } @@ -781,15 +708,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int assert(_PyInterpreterFrame_LASTI(frame) >= -1); \ /* Jump back to the last instruction executed... */ \ next_instr = frame->prev_instr + 1; \ - stack_pointer = _PyFrame_GetStackPointer(frame); \ - /* Set stackdepth to -1. \ - Update when returning or calling trace function. \ - Having stackdepth <= 0 ensures that invalid \ - values are not visible to the cycle GC. \ - We choose -1 rather than 0 to assist debugging. \ - */ \ - frame->stacktop = -1; - + stack_pointer = _PyFrame_GetStackPointer(frame); start_frame: if (_Py_EnterRecursivePy(tstate)) { @@ -845,91 +764,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int #include "generated_cases.c.h" -#if USE_COMPUTED_GOTOS - TARGET_DO_TRACING: -#else - case DO_TRACING: -#endif - { - assert(cframe.use_tracing); - assert(tstate->tracing == 0); - if (INSTR_OFFSET() >= frame->f_code->_co_firsttraceable) { - int instr_prev = _PyInterpreterFrame_LASTI(frame); - frame->prev_instr = next_instr; - NEXTOPARG(); - // No _PyOpcode_Deopt here, since RESUME has no optimized forms: - if (opcode == RESUME) { - if (oparg < 2) { - CHECK_EVAL_BREAKER(); - } - /* Call tracing */ - TRACE_FUNCTION_ENTRY(); - DTRACE_FUNCTION_ENTRY(); - } - else { - /* line-by-line tracing support */ - if (PyDTrace_LINE_ENABLED()) { - maybe_dtrace_line(frame, &tstate->trace_info, instr_prev); - } - - if (cframe.use_tracing && - tstate->c_tracefunc != NULL && !tstate->tracing) { - int err; - /* see maybe_call_line_trace() - for expository comments */ - _PyFrame_SetStackPointer(frame, stack_pointer); - - err = maybe_call_line_trace(tstate->c_tracefunc, - tstate->c_traceobj, - tstate, frame, instr_prev); - // Reload possibly changed frame fields: - stack_pointer = _PyFrame_GetStackPointer(frame); - frame->stacktop = -1; - // next_instr is only reloaded if tracing *does not* raise. - // This is consistent with the behavior of older Python - // versions. If a trace function sets a new f_lineno and - // *then* raises, we use the *old* location when searching - // for an exception handler, displaying the traceback, and - // so on: - if (err) { - // next_instr wasn't incremented at the start of this - // instruction. Increment it before handling the error, - // so that it looks the same as a "normal" instruction: - next_instr++; - goto error; - } - // Reload next_instr. Don't increment it, though, since - // we're going to re-dispatch to the "true" instruction now: - next_instr = frame->prev_instr; - } - } - } - NEXTOPARG(); - PRE_DISPATCH_GOTO(); - // No _PyOpcode_Deopt here, since EXTENDED_ARG has no optimized forms: - while (opcode == EXTENDED_ARG) { - // CPython hasn't ever traced the instruction after an EXTENDED_ARG. - // Inline the EXTENDED_ARG here, so we can avoid branching there: - INSTRUCTION_START(EXTENDED_ARG); - opcode = next_instr->op.code; - oparg = oparg << 8 | next_instr->op.arg; - // Make sure the next instruction isn't a RESUME, since that needs - // to trace properly (and shouldn't have an EXTENDED_ARG, anyways): - assert(opcode != RESUME); - PRE_DISPATCH_GOTO(); - } - opcode = _PyOpcode_Deopt[opcode]; - if (_PyOpcode_Caches[opcode]) { - uint16_t *counter = &next_instr[1].cache; - // The instruction is going to decrement the counter, so we need to - // increment it here to make sure it doesn't try to specialize: - if (!ADAPTIVE_COUNTER_IS_MAX(*counter)) { - INCREMENT_ADAPTIVE_COUNTER(*counter); - } - } - DISPATCH_GOTO(); - } - #if USE_COMPUTED_GOTOS _unknown_opcode: #else @@ -988,12 +822,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int PyTraceBack_Here(f); } } - - if (tstate->c_tracefunc != NULL) { - /* Make sure state is set to FRAME_UNWINDING for tracing */ - call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, - tstate, frame); - } + monitor_raise(tstate, frame, next_instr-1); exception_unwind: { @@ -1012,8 +841,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } assert(STACK_LEVEL() == 0); _PyFrame_SetStackPointer(frame, stack_pointer); - TRACE_FUNCTION_UNWIND(); - DTRACE_FUNCTION_EXIT(); + monitor_unwind(tstate, frame, next_instr-1); goto exit_unwind; } @@ -1036,8 +864,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int available to the handler, so a program can emulate the Python main loop. */ - PUSH(_PyErr_GetRaisedException(tstate)); + PyObject *exc = _PyErr_GetRaisedException(tstate); + PUSH(exc); JUMPTO(handler); + monitor_handled(tstate, frame, next_instr, exc); /* Resume normal execution */ DISPATCH(); } @@ -1054,7 +884,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int if (frame == &entry_frame) { /* Restore previous cframe and exit */ tstate->cframe = cframe.previous; - tstate->cframe->use_tracing = cframe.use_tracing; assert(tstate->cframe->current_frame == frame->previous); _Py_LeaveRecursiveCallTstate(tstate); return NULL; @@ -2020,105 +1849,108 @@ unpack_iterable(PyThreadState *tstate, PyObject *v, return 0; } -static void -call_exc_trace(Py_tracefunc func, PyObject *self, - PyThreadState *tstate, - _PyInterpreterFrame *f) +static int +do_monitor_exc(PyThreadState *tstate, _PyInterpreterFrame *frame, + _Py_CODEUNIT *instr, int event) { - PyObject *exc = _PyErr_GetRaisedException(tstate); - assert(exc && PyExceptionInstance_Check(exc)); - PyObject *type = PyExceptionInstance_Class(exc); - PyObject *traceback = PyException_GetTraceback(exc); - if (traceback == NULL) { - traceback = Py_NewRef(Py_None); + assert(event < PY_MONITORING_UNGROUPED_EVENTS); + PyObject *exc = PyErr_GetRaisedException(); + assert(exc != NULL); + int err = _Py_call_instrumentation_arg(tstate, event, frame, instr, exc); + if (err == 0) { + PyErr_SetRaisedException(exc); } - PyObject *arg = PyTuple_Pack(3, type, exc, traceback); - Py_XDECREF(traceback); - - if (arg == NULL) { - _PyErr_SetRaisedException(tstate, exc); - return; + else { + Py_DECREF(exc); } - int err = call_trace(func, self, tstate, f, PyTrace_EXCEPTION, arg); - Py_DECREF(arg); - if (err == 0) { - _PyErr_SetRaisedException(tstate, exc); + return err; +} + +static inline int +no_tools_for_event(PyThreadState *tstate, _PyInterpreterFrame *frame, int event) +{ + _PyCoMonitoringData *data = frame->f_code->_co_monitoring; + if (data) { + if (data->active_monitors.tools[event] == 0) { + return 1; + } } else { - Py_XDECREF(exc); + if (tstate->interp->monitors.tools[event] == 0) { + return 1; + } + } + return 0; +} + +static void +monitor_raise(PyThreadState *tstate, _PyInterpreterFrame *frame, + _Py_CODEUNIT *instr) +{ + if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_RAISE)) { + return; } + do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_RAISE); } static int -call_trace_protected(Py_tracefunc func, PyObject *obj, - PyThreadState *tstate, _PyInterpreterFrame *frame, - int what, PyObject *arg) +monitor_stop_iteration(PyThreadState *tstate, _PyInterpreterFrame *frame, + _Py_CODEUNIT *instr) { - PyObject *exc = _PyErr_GetRaisedException(tstate); - int err = call_trace(func, obj, tstate, frame, what, arg); - if (err == 0) - { - _PyErr_SetRaisedException(tstate, exc); + if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_STOP_ITERATION)) { return 0; } - else { - Py_XDECREF(exc); - return -1; + return do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_STOP_ITERATION); +} + +static void +monitor_unwind(PyThreadState *tstate, + _PyInterpreterFrame *frame, + _Py_CODEUNIT *instr) +{ + if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_PY_UNWIND)) { + return; } + _Py_call_instrumentation_exc0(tstate, PY_MONITORING_EVENT_PY_UNWIND, frame, instr); } + static void -initialize_trace_info(PyTraceInfo *trace_info, _PyInterpreterFrame *frame) +monitor_handled(PyThreadState *tstate, + _PyInterpreterFrame *frame, + _Py_CODEUNIT *instr, PyObject *exc) { - PyCodeObject *code = frame->f_code; - if (trace_info->code != code) { - trace_info->code = code; - _PyCode_InitAddressRange(code, &trace_info->bounds); + if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_EXCEPTION_HANDLED)) { + return; } + _Py_call_instrumentation_arg(tstate, PY_MONITORING_EVENT_EXCEPTION_HANDLED, frame, instr, exc); +} + +static void +monitor_throw(PyThreadState *tstate, + _PyInterpreterFrame *frame, + _Py_CODEUNIT *instr) +{ + if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_PY_THROW)) { + return; + } + _Py_call_instrumentation_exc0(tstate, PY_MONITORING_EVENT_PY_THROW, frame, instr); } void PyThreadState_EnterTracing(PyThreadState *tstate) { + assert(tstate->tracing >= 0); tstate->tracing++; - tstate->cframe->use_tracing = 0; } void PyThreadState_LeaveTracing(PyThreadState *tstate) { - assert(tstate->tracing > 0 && tstate->cframe->use_tracing == 0); + assert(tstate->tracing > 0); tstate->tracing--; - _PyThreadState_UpdateTracingState(tstate); } -static int -call_trace(Py_tracefunc func, PyObject *obj, - PyThreadState *tstate, _PyInterpreterFrame *frame, - int what, PyObject *arg) -{ - int result; - if (tstate->tracing) { - return 0; - } - PyFrameObject *f = _PyFrame_GetFrameObject(frame); - if (f == NULL) { - return -1; - } - int old_what = tstate->tracing_what; - tstate->tracing_what = what; - PyThreadState_EnterTracing(tstate); - assert(_PyInterpreterFrame_LASTI(frame) >= 0); - if (_PyCode_InitLineArray(frame->f_code)) { - return -1; - } - f->f_lineno = _PyCode_LineNumberFromArray(frame->f_code, _PyInterpreterFrame_LASTI(frame)); - result = func(obj, f, what, arg); - f->f_lineno = 0; - PyThreadState_LeaveTracing(tstate); - tstate->tracing_what = old_what; - return result; -} PyObject* _PyEval_CallTracing(PyObject *func, PyObject *args) @@ -2126,7 +1958,6 @@ _PyEval_CallTracing(PyObject *func, PyObject *args) // Save and disable tracing PyThreadState *tstate = _PyThreadState_GET(); int save_tracing = tstate->tracing; - int save_use_tracing = tstate->cframe->use_tracing; tstate->tracing = 0; // Call the tracing function @@ -2134,81 +1965,9 @@ _PyEval_CallTracing(PyObject *func, PyObject *args) // Restore tracing tstate->tracing = save_tracing; - tstate->cframe->use_tracing = save_use_tracing; return result; } -/* See Objects/lnotab_notes.txt for a description of how tracing works. */ -static int -maybe_call_line_trace(Py_tracefunc func, PyObject *obj, - PyThreadState *tstate, _PyInterpreterFrame *frame, int instr_prev) -{ - int result = 0; - - /* If the last instruction falls at the start of a line or if it - represents a jump backwards, update the frame's line number and - then call the trace function if we're tracing source lines. - */ - if (_PyCode_InitLineArray(frame->f_code)) { - return -1; - } - int lastline; - if (instr_prev <= frame->f_code->_co_firsttraceable) { - lastline = -1; - } - else { - lastline = _PyCode_LineNumberFromArray(frame->f_code, instr_prev); - } - int line = _PyCode_LineNumberFromArray(frame->f_code, _PyInterpreterFrame_LASTI(frame)); - PyFrameObject *f = _PyFrame_GetFrameObject(frame); - if (f == NULL) { - return -1; - } - if (line != -1 && f->f_trace_lines) { - /* Trace backward edges (except in 'yield from') or if line number has changed */ - int trace = line != lastline || - (_PyInterpreterFrame_LASTI(frame) < instr_prev && - // SEND has no quickened forms, so no need to use _PyOpcode_Deopt - // here: - frame->prev_instr->op.code != SEND); - if (trace) { - result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None); - } - } - /* Always emit an opcode event if we're tracing all opcodes. */ - if (f->f_trace_opcodes && result == 0) { - result = call_trace(func, obj, tstate, frame, PyTrace_OPCODE, Py_None); - } - return result; -} - -int -_PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) -{ - assert(is_tstate_valid(tstate)); - /* The caller must hold the GIL */ - assert(PyGILState_Check()); - - /* Call _PySys_Audit() in the context of the current thread state, - even if tstate is not the current thread state. */ - PyThreadState *current_tstate = _PyThreadState_GET(); - if (_PySys_Audit(current_tstate, "sys.setprofile", NULL) < 0) { - return -1; - } - - tstate->c_profilefunc = func; - PyObject *old_profileobj = tstate->c_profileobj; - tstate->c_profileobj = Py_XNewRef(arg); - /* Flag that tracing or profiling is turned on */ - _PyThreadState_UpdateTracingState(tstate); - - // gh-98257: Only call Py_XDECREF() once the new profile function is fully - // set, so it's safe to call sys.setprofile() again (reentrant call). - Py_XDECREF(old_profileobj); - - return 0; -} - void PyEval_SetProfile(Py_tracefunc func, PyObject *arg) { @@ -2240,33 +1999,6 @@ PyEval_SetProfileAllThreads(Py_tracefunc func, PyObject *arg) } } -int -_PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) -{ - assert(is_tstate_valid(tstate)); - /* The caller must hold the GIL */ - assert(PyGILState_Check()); - - /* Call _PySys_Audit() in the context of the current thread state, - even if tstate is not the current thread state. */ - PyThreadState *current_tstate = _PyThreadState_GET(); - if (_PySys_Audit(current_tstate, "sys.settrace", NULL) < 0) { - return -1; - } - - tstate->c_tracefunc = func; - PyObject *old_traceobj = tstate->c_traceobj; - tstate->c_traceobj = Py_XNewRef(arg); - /* Flag that tracing or profiling is turned on */ - _PyThreadState_UpdateTracingState(tstate); - - // gh-98257: Only call Py_XDECREF() once the new trace function is fully - // set, so it's safe to call sys.settrace() again (reentrant call). - Py_XDECREF(old_traceobj); - - return 0; -} - void PyEval_SetTrace(Py_tracefunc func, PyObject *arg) { @@ -2492,114 +2224,6 @@ PyEval_GetFuncDesc(PyObject *func) return " object"; } -#define C_TRACE(x, call) \ -if (use_tracing && tstate->c_profilefunc) { \ - if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \ - tstate, tstate->cframe->current_frame, \ - PyTrace_C_CALL, func)) { \ - x = NULL; \ - } \ - else { \ - x = call; \ - if (tstate->c_profilefunc != NULL) { \ - if (x == NULL) { \ - call_trace_protected(tstate->c_profilefunc, \ - tstate->c_profileobj, \ - tstate, tstate->cframe->current_frame, \ - PyTrace_C_EXCEPTION, func); \ - /* XXX should pass (type, value, tb) */ \ - } else { \ - if (call_trace(tstate->c_profilefunc, \ - tstate->c_profileobj, \ - tstate, tstate->cframe->current_frame, \ - PyTrace_C_RETURN, func)) { \ - Py_DECREF(x); \ - x = NULL; \ - } \ - } \ - } \ - } \ -} else { \ - x = call; \ - } - - -static PyObject * -trace_call_function(PyThreadState *tstate, - PyObject *func, - PyObject **args, Py_ssize_t nargs, - PyObject *kwnames) -{ - int use_tracing = 1; - PyObject *x; - if (PyCFunction_CheckExact(func) || PyCMethod_CheckExact(func)) { - C_TRACE(x, PyObject_Vectorcall(func, args, nargs, kwnames)); - return x; - } - else if (Py_IS_TYPE(func, &PyMethodDescr_Type) && nargs > 0) { - /* We need to create a temporary bound method as argument - for profiling. - - If nargs == 0, then this cannot work because we have no - "self". In any case, the call itself would raise - TypeError (foo needs an argument), so we just skip - profiling. */ - PyObject *self = args[0]; - func = Py_TYPE(func)->tp_descr_get(func, self, (PyObject*)Py_TYPE(self)); - if (func == NULL) { - return NULL; - } - C_TRACE(x, PyObject_Vectorcall(func, - args+1, nargs-1, - kwnames)); - Py_DECREF(func); - return x; - } - return PyObject_Vectorcall(func, args, nargs | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames); -} - -static PyObject * -do_call_core(PyThreadState *tstate, - PyObject *func, - PyObject *callargs, - PyObject *kwdict, - int use_tracing - ) -{ - PyObject *result; - if (PyCFunction_CheckExact(func) || PyCMethod_CheckExact(func)) { - C_TRACE(result, PyObject_Call(func, callargs, kwdict)); - return result; - } - else if (Py_IS_TYPE(func, &PyMethodDescr_Type)) { - Py_ssize_t nargs = PyTuple_GET_SIZE(callargs); - if (nargs > 0 && use_tracing) { - /* We need to create a temporary bound method as argument - for profiling. - - If nargs == 0, then this cannot work because we have no - "self". In any case, the call itself would raise - TypeError (foo needs an argument), so we just skip - profiling. */ - PyObject *self = PyTuple_GET_ITEM(callargs, 0); - func = Py_TYPE(func)->tp_descr_get(func, self, (PyObject*)Py_TYPE(self)); - if (func == NULL) { - return NULL; - } - - C_TRACE(result, _PyObject_FastCallDictTstate( - tstate, func, - &_PyTuple_ITEMS(callargs)[1], - nargs - 1, - kwdict)); - Py_DECREF(func); - return result; - } - } - EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func); - return PyObject_Call(func, callargs, kwdict); -} - /* Extract a slice index from a PyLong or an object with the nb_index slot defined, and store in *pi. Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX, @@ -2973,69 +2597,6 @@ PyUnstable_Eval_RequestCodeExtraIndex(freefunc free) return new_index; } -static void -dtrace_function_entry(_PyInterpreterFrame *frame) -{ - const char *filename; - const char *funcname; - int lineno; - - PyCodeObject *code = frame->f_code; - filename = PyUnicode_AsUTF8(code->co_filename); - funcname = PyUnicode_AsUTF8(code->co_name); - lineno = _PyInterpreterFrame_GetLine(frame); - - PyDTrace_FUNCTION_ENTRY(filename, funcname, lineno); -} - -static void -dtrace_function_return(_PyInterpreterFrame *frame) -{ - const char *filename; - const char *funcname; - int lineno; - - PyCodeObject *code = frame->f_code; - filename = PyUnicode_AsUTF8(code->co_filename); - funcname = PyUnicode_AsUTF8(code->co_name); - lineno = _PyInterpreterFrame_GetLine(frame); - - PyDTrace_FUNCTION_RETURN(filename, funcname, lineno); -} - -/* DTrace equivalent of maybe_call_line_trace. */ -static void -maybe_dtrace_line(_PyInterpreterFrame *frame, - PyTraceInfo *trace_info, - int instr_prev) -{ - const char *co_filename, *co_name; - - /* If the last instruction executed isn't in the current - instruction window, reset the window. - */ - initialize_trace_info(trace_info, frame); - int lastline = _PyCode_CheckLineNumber(instr_prev*sizeof(_Py_CODEUNIT), &trace_info->bounds); - int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); - int line = _PyCode_CheckLineNumber(addr, &trace_info->bounds); - if (line != -1) { - /* Trace backward edges or first instruction of a new line */ - if (_PyInterpreterFrame_LASTI(frame) < instr_prev || - (line != lastline && addr == trace_info->bounds.ar_start)) - { - co_filename = PyUnicode_AsUTF8(frame->f_code->co_filename); - if (!co_filename) { - co_filename = "?"; - } - co_name = PyUnicode_AsUTF8(frame->f_code->co_name); - if (!co_name) { - co_name = "?"; - } - PyDTrace_LINE(co_filename, co_name, line); - } - } -} - /* Implement Py_EnterRecursiveCall() and Py_LeaveRecursiveCall() as functions for the limited API. */ diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index c2257515a305..485771ac65a7 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -93,8 +93,6 @@ { \ NEXTOPARG(); \ PRE_DISPATCH_GOTO(); \ - assert(cframe.use_tracing == 0 || cframe.use_tracing == 255); \ - opcode |= cframe.use_tracing OR_DTRACE_LINE; \ DISPATCH_GOTO(); \ } @@ -102,7 +100,6 @@ { \ opcode = next_instr->op.code; \ PRE_DISPATCH_GOTO(); \ - opcode |= cframe.use_tracing OR_DTRACE_LINE; \ DISPATCH_GOTO(); \ } @@ -183,7 +180,7 @@ GETITEM(PyObject *v, Py_ssize_t i) { #define PREDICT(next_op) \ do { \ _Py_CODEUNIT word = *next_instr; \ - opcode = word.op.code | cframe.use_tracing OR_DTRACE_LINE; \ + opcode = word.op.code; \ if (opcode == next_op) { \ oparg = word.op.arg; \ INSTRUCTION_START(next_op); \ @@ -283,47 +280,6 @@ GETITEM(PyObject *v, Py_ssize_t i) { #define BUILTINS() frame->f_builtins #define LOCALS() frame->f_locals -/* Shared opcode macros */ - -#define TRACE_FUNCTION_EXIT() \ - if (cframe.use_tracing) { \ - if (trace_function_exit(tstate, frame, retval)) { \ - Py_DECREF(retval); \ - goto exit_unwind; \ - } \ - } - -#define DTRACE_FUNCTION_EXIT() \ - if (PyDTrace_FUNCTION_RETURN_ENABLED()) { \ - dtrace_function_return(frame); \ - } - -#define TRACE_FUNCTION_UNWIND() \ - if (cframe.use_tracing) { \ - /* Since we are already unwinding, \ - * we don't care if this raises */ \ - trace_function_exit(tstate, frame, NULL); \ - } - -#define TRACE_FUNCTION_ENTRY() \ - if (cframe.use_tracing) { \ - _PyFrame_SetStackPointer(frame, stack_pointer); \ - int err = trace_function_entry(tstate, frame); \ - stack_pointer = _PyFrame_GetStackPointer(frame); \ - frame->stacktop = -1; \ - if (err) { \ - goto error; \ - } \ - } - -#define TRACE_FUNCTION_THROW_ENTRY() \ - if (cframe.use_tracing) { \ - assert(frame->stacktop >= 0); \ - if (trace_function_entry(tstate, frame)) { \ - goto exit_unwind; \ - } \ - } - #define DTRACE_FUNCTION_ENTRY() \ if (PyDTrace_FUNCTION_ENTRY_ENABLED()) { \ dtrace_function_entry(frame); \ @@ -371,3 +327,18 @@ do { \ _Py_DECREF_NO_DEALLOC(right); \ } \ } while (0) + +// If a trace function sets a new f_lineno and +// *then* raises, we use the destination when searching +// for an exception handler, displaying the traceback, and so on +#define INSTRUMENTED_JUMP(src, dest, event) \ +do { \ + _PyFrame_SetStackPointer(frame, stack_pointer); \ + int err = _Py_call_instrumentation_jump(tstate, event, frame, src, dest); \ + stack_pointer = _PyFrame_GetStackPointer(frame); \ + if (err) { \ + next_instr = (dest)+1; \ + goto error; \ + } \ + next_instr = frame->prev_instr; \ +} while (0); diff --git a/Python/clinic/instrumentation.c.h b/Python/clinic/instrumentation.c.h new file mode 100644 index 000000000000..cf3984ca24bb --- /dev/null +++ b/Python/clinic/instrumentation.c.h @@ -0,0 +1,311 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif + + +PyDoc_STRVAR(monitoring_use_tool_id__doc__, +"use_tool_id($module, tool_id, name, /)\n" +"--\n" +"\n"); + +#define MONITORING_USE_TOOL_ID_METHODDEF \ + {"use_tool_id", _PyCFunction_CAST(monitoring_use_tool_id), METH_FASTCALL, monitoring_use_tool_id__doc__}, + +static PyObject * +monitoring_use_tool_id_impl(PyObject *module, int tool_id, PyObject *name); + +static PyObject * +monitoring_use_tool_id(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int tool_id; + PyObject *name; + + if (!_PyArg_CheckPositional("use_tool_id", nargs, 2, 2)) { + goto exit; + } + tool_id = _PyLong_AsInt(args[0]); + if (tool_id == -1 && PyErr_Occurred()) { + goto exit; + } + name = args[1]; + return_value = monitoring_use_tool_id_impl(module, tool_id, name); + +exit: + return return_value; +} + +PyDoc_STRVAR(monitoring_free_tool_id__doc__, +"free_tool_id($module, tool_id, /)\n" +"--\n" +"\n"); + +#define MONITORING_FREE_TOOL_ID_METHODDEF \ + {"free_tool_id", (PyCFunction)monitoring_free_tool_id, METH_O, monitoring_free_tool_id__doc__}, + +static PyObject * +monitoring_free_tool_id_impl(PyObject *module, int tool_id); + +static PyObject * +monitoring_free_tool_id(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + int tool_id; + + tool_id = _PyLong_AsInt(arg); + if (tool_id == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = monitoring_free_tool_id_impl(module, tool_id); + +exit: + return return_value; +} + +PyDoc_STRVAR(monitoring_get_tool__doc__, +"get_tool($module, tool_id, /)\n" +"--\n" +"\n"); + +#define MONITORING_GET_TOOL_METHODDEF \ + {"get_tool", (PyCFunction)monitoring_get_tool, METH_O, monitoring_get_tool__doc__}, + +static PyObject * +monitoring_get_tool_impl(PyObject *module, int tool_id); + +static PyObject * +monitoring_get_tool(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + int tool_id; + + tool_id = _PyLong_AsInt(arg); + if (tool_id == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = monitoring_get_tool_impl(module, tool_id); + +exit: + return return_value; +} + +PyDoc_STRVAR(monitoring_register_callback__doc__, +"register_callback($module, tool_id, event, func, /)\n" +"--\n" +"\n"); + +#define MONITORING_REGISTER_CALLBACK_METHODDEF \ + {"register_callback", _PyCFunction_CAST(monitoring_register_callback), METH_FASTCALL, monitoring_register_callback__doc__}, + +static PyObject * +monitoring_register_callback_impl(PyObject *module, int tool_id, int event, + PyObject *func); + +static PyObject * +monitoring_register_callback(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int tool_id; + int event; + PyObject *func; + + if (!_PyArg_CheckPositional("register_callback", nargs, 3, 3)) { + goto exit; + } + tool_id = _PyLong_AsInt(args[0]); + if (tool_id == -1 && PyErr_Occurred()) { + goto exit; + } + event = _PyLong_AsInt(args[1]); + if (event == -1 && PyErr_Occurred()) { + goto exit; + } + func = args[2]; + return_value = monitoring_register_callback_impl(module, tool_id, event, func); + +exit: + return return_value; +} + +PyDoc_STRVAR(monitoring_get_events__doc__, +"get_events($module, tool_id, /)\n" +"--\n" +"\n"); + +#define MONITORING_GET_EVENTS_METHODDEF \ + {"get_events", (PyCFunction)monitoring_get_events, METH_O, monitoring_get_events__doc__}, + +static int +monitoring_get_events_impl(PyObject *module, int tool_id); + +static PyObject * +monitoring_get_events(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + int tool_id; + int _return_value; + + tool_id = _PyLong_AsInt(arg); + if (tool_id == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = monitoring_get_events_impl(module, tool_id); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyLong_FromLong((long)_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(monitoring_set_events__doc__, +"set_events($module, tool_id, event_set, /)\n" +"--\n" +"\n"); + +#define MONITORING_SET_EVENTS_METHODDEF \ + {"set_events", _PyCFunction_CAST(monitoring_set_events), METH_FASTCALL, monitoring_set_events__doc__}, + +static PyObject * +monitoring_set_events_impl(PyObject *module, int tool_id, int event_set); + +static PyObject * +monitoring_set_events(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int tool_id; + int event_set; + + if (!_PyArg_CheckPositional("set_events", nargs, 2, 2)) { + goto exit; + } + tool_id = _PyLong_AsInt(args[0]); + if (tool_id == -1 && PyErr_Occurred()) { + goto exit; + } + event_set = _PyLong_AsInt(args[1]); + if (event_set == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = monitoring_set_events_impl(module, tool_id, event_set); + +exit: + return return_value; +} + +PyDoc_STRVAR(monitoring_get_local_events__doc__, +"get_local_events($module, tool_id, code, /)\n" +"--\n" +"\n"); + +#define MONITORING_GET_LOCAL_EVENTS_METHODDEF \ + {"get_local_events", _PyCFunction_CAST(monitoring_get_local_events), METH_FASTCALL, monitoring_get_local_events__doc__}, + +static int +monitoring_get_local_events_impl(PyObject *module, int tool_id, + PyObject *code); + +static PyObject * +monitoring_get_local_events(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int tool_id; + PyObject *code; + int _return_value; + + if (!_PyArg_CheckPositional("get_local_events", nargs, 2, 2)) { + goto exit; + } + tool_id = _PyLong_AsInt(args[0]); + if (tool_id == -1 && PyErr_Occurred()) { + goto exit; + } + code = args[1]; + _return_value = monitoring_get_local_events_impl(module, tool_id, code); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyLong_FromLong((long)_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(monitoring_set_local_events__doc__, +"set_local_events($module, tool_id, code, event_set, /)\n" +"--\n" +"\n"); + +#define MONITORING_SET_LOCAL_EVENTS_METHODDEF \ + {"set_local_events", _PyCFunction_CAST(monitoring_set_local_events), METH_FASTCALL, monitoring_set_local_events__doc__}, + +static PyObject * +monitoring_set_local_events_impl(PyObject *module, int tool_id, + PyObject *code, int event_set); + +static PyObject * +monitoring_set_local_events(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int tool_id; + PyObject *code; + int event_set; + + if (!_PyArg_CheckPositional("set_local_events", nargs, 3, 3)) { + goto exit; + } + tool_id = _PyLong_AsInt(args[0]); + if (tool_id == -1 && PyErr_Occurred()) { + goto exit; + } + code = args[1]; + event_set = _PyLong_AsInt(args[2]); + if (event_set == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = monitoring_set_local_events_impl(module, tool_id, code, event_set); + +exit: + return return_value; +} + +PyDoc_STRVAR(monitoring_restart_events__doc__, +"restart_events($module, /)\n" +"--\n" +"\n"); + +#define MONITORING_RESTART_EVENTS_METHODDEF \ + {"restart_events", (PyCFunction)monitoring_restart_events, METH_NOARGS, monitoring_restart_events__doc__}, + +static PyObject * +monitoring_restart_events_impl(PyObject *module); + +static PyObject * +monitoring_restart_events(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return monitoring_restart_events_impl(module); +} + +PyDoc_STRVAR(monitoring__all_events__doc__, +"_all_events($module, /)\n" +"--\n" +"\n"); + +#define MONITORING__ALL_EVENTS_METHODDEF \ + {"_all_events", (PyCFunction)monitoring__all_events, METH_NOARGS, monitoring__all_events__doc__}, + +static PyObject * +monitoring__all_events_impl(PyObject *module); + +static PyObject * +monitoring__all_events(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return monitoring__all_events_impl(module); +} +/*[clinic end generated code: output=11cc0803875b3ffa input=a9049054013a1b77]*/ diff --git a/Python/compile.c b/Python/compile.c index 3e152060d2f1..d6882c31d643 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1427,8 +1427,7 @@ compiler_add_yield_from(struct compiler *c, location loc, int await) ADDOP(c, loc, CLEANUP_THROW); USE_LABEL(c, exit); - ADDOP_I(c, loc, SWAP, 2); - ADDOP(c, loc, POP_TOP); + ADDOP(c, loc, END_SEND); return SUCCESS; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 420d136bb981..4d52e95dc04a 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -8,24 +8,61 @@ } TARGET(RESUME) { - #line 135 "Python/bytecodes.c" + #line 136 "Python/bytecodes.c" assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); - if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { + /* Possibly combine this with eval breaker */ + if (frame->f_code->_co_instrumentation_version != tstate->interp->monitoring_version) { + int err = _Py_Instrument(frame->f_code, tstate->interp); + if (err) goto error; + next_instr--; + } + else if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { goto handle_eval_breaker; } - #line 18 "Python/generated_cases.c.h" + #line 24 "Python/generated_cases.c.h" + DISPATCH(); + } + + TARGET(INSTRUMENTED_RESUME) { + #line 150 "Python/bytecodes.c" + /* Possible performance enhancement: + * We need to check the eval breaker anyway, can we + * combine the instrument verison check and the eval breaker test? + */ + if (frame->f_code->_co_instrumentation_version != tstate->interp->monitoring_version) { + if (_Py_Instrument(frame->f_code, tstate->interp)) { + goto error; + } + next_instr--; + } + else { + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_call_instrumentation( + tstate, oparg > 0, frame, next_instr-1); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err) goto error; + if (frame->prev_instr != next_instr-1) { + /* Instrumentation has jumped */ + next_instr = frame->prev_instr; + DISPATCH(); + } + if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { + goto handle_eval_breaker; + } + } + #line 55 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_CLOSURE) { PyObject *value; - #line 143 "Python/bytecodes.c" + #line 178 "Python/bytecodes.c" /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); - #line 29 "Python/generated_cases.c.h" + #line 66 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -33,11 +70,11 @@ TARGET(LOAD_FAST_CHECK) { PyObject *value; - #line 150 "Python/bytecodes.c" + #line 185 "Python/bytecodes.c" value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); - #line 41 "Python/generated_cases.c.h" + #line 78 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -45,11 +82,11 @@ TARGET(LOAD_FAST) { PyObject *value; - #line 156 "Python/bytecodes.c" + #line 191 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); - #line 53 "Python/generated_cases.c.h" + #line 90 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -58,10 +95,10 @@ TARGET(LOAD_CONST) { PREDICTED(LOAD_CONST); PyObject *value; - #line 162 "Python/bytecodes.c" + #line 197 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); - #line 65 "Python/generated_cases.c.h" + #line 102 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -69,9 +106,9 @@ TARGET(STORE_FAST) { PyObject *value = stack_pointer[-1]; - #line 167 "Python/bytecodes.c" + #line 202 "Python/bytecodes.c" SETLOCAL(oparg, value); - #line 75 "Python/generated_cases.c.h" + #line 112 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -81,21 +118,21 @@ PyObject *_tmp_2; { PyObject *value; - #line 156 "Python/bytecodes.c" + #line 191 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); - #line 89 "Python/generated_cases.c.h" + #line 126 "Python/generated_cases.c.h" _tmp_2 = value; } oparg = (next_instr++)->op.arg; { PyObject *value; - #line 156 "Python/bytecodes.c" + #line 191 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); - #line 99 "Python/generated_cases.c.h" + #line 136 "Python/generated_cases.c.h" _tmp_1 = value; } STACK_GROW(2); @@ -109,20 +146,20 @@ PyObject *_tmp_2; { PyObject *value; - #line 156 "Python/bytecodes.c" + #line 191 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); - #line 117 "Python/generated_cases.c.h" + #line 154 "Python/generated_cases.c.h" _tmp_2 = value; } oparg = (next_instr++)->op.arg; { PyObject *value; - #line 162 "Python/bytecodes.c" + #line 197 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); - #line 126 "Python/generated_cases.c.h" + #line 163 "Python/generated_cases.c.h" _tmp_1 = value; } STACK_GROW(2); @@ -135,18 +172,18 @@ PyObject *_tmp_1 = stack_pointer[-1]; { PyObject *value = _tmp_1; - #line 167 "Python/bytecodes.c" + #line 202 "Python/bytecodes.c" SETLOCAL(oparg, value); - #line 141 "Python/generated_cases.c.h" + #line 178 "Python/generated_cases.c.h" } oparg = (next_instr++)->op.arg; { PyObject *value; - #line 156 "Python/bytecodes.c" + #line 191 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); - #line 150 "Python/generated_cases.c.h" + #line 187 "Python/generated_cases.c.h" _tmp_1 = value; } stack_pointer[-1] = _tmp_1; @@ -158,16 +195,16 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; - #line 167 "Python/bytecodes.c" + #line 202 "Python/bytecodes.c" SETLOCAL(oparg, value); - #line 164 "Python/generated_cases.c.h" + #line 201 "Python/generated_cases.c.h" } oparg = (next_instr++)->op.arg; { PyObject *value = _tmp_2; - #line 167 "Python/bytecodes.c" + #line 202 "Python/bytecodes.c" SETLOCAL(oparg, value); - #line 171 "Python/generated_cases.c.h" + #line 208 "Python/generated_cases.c.h" } STACK_SHRINK(2); DISPATCH(); @@ -178,20 +215,20 @@ PyObject *_tmp_2; { PyObject *value; - #line 162 "Python/bytecodes.c" + #line 197 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); - #line 185 "Python/generated_cases.c.h" + #line 222 "Python/generated_cases.c.h" _tmp_2 = value; } oparg = (next_instr++)->op.arg; { PyObject *value; - #line 156 "Python/bytecodes.c" + #line 191 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); - #line 195 "Python/generated_cases.c.h" + #line 232 "Python/generated_cases.c.h" _tmp_1 = value; } STACK_GROW(2); @@ -202,8 +239,8 @@ TARGET(POP_TOP) { PyObject *value = stack_pointer[-1]; - #line 177 "Python/bytecodes.c" - #line 207 "Python/generated_cases.c.h" + #line 212 "Python/bytecodes.c" + #line 244 "Python/generated_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); DISPATCH(); @@ -211,9 +248,9 @@ TARGET(PUSH_NULL) { PyObject *res; - #line 181 "Python/bytecodes.c" + #line 216 "Python/bytecodes.c" res = NULL; - #line 217 "Python/generated_cases.c.h" + #line 254 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -224,30 +261,79 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; - #line 177 "Python/bytecodes.c" - #line 229 "Python/generated_cases.c.h" + #line 212 "Python/bytecodes.c" + #line 266 "Python/generated_cases.c.h" Py_DECREF(value); } { PyObject *value = _tmp_2; - #line 177 "Python/bytecodes.c" - #line 235 "Python/generated_cases.c.h" + #line 212 "Python/bytecodes.c" + #line 272 "Python/generated_cases.c.h" Py_DECREF(value); } STACK_SHRINK(2); DISPATCH(); } + TARGET(INSTRUMENTED_END_FOR) { + PyObject *value = stack_pointer[-1]; + PyObject *receiver = stack_pointer[-2]; + #line 222 "Python/bytecodes.c" + /* Need to create a fake StopIteration error here, + * to conform to PEP 380 */ + if (PyGen_Check(receiver)) { + PyErr_SetObject(PyExc_StopIteration, value); + if (monitor_stop_iteration(tstate, frame, next_instr-1)) { + goto error; + } + PyErr_SetRaisedException(NULL); + } + #line 292 "Python/generated_cases.c.h" + Py_DECREF(receiver); + Py_DECREF(value); + STACK_SHRINK(2); + DISPATCH(); + } + + TARGET(END_SEND) { + PyObject *value = stack_pointer[-1]; + PyObject *receiver = stack_pointer[-2]; + #line 235 "Python/bytecodes.c" + Py_DECREF(receiver); + #line 304 "Python/generated_cases.c.h" + STACK_SHRINK(1); + stack_pointer[-1] = value; + DISPATCH(); + } + + TARGET(INSTRUMENTED_END_SEND) { + PyObject *value = stack_pointer[-1]; + PyObject *receiver = stack_pointer[-2]; + #line 239 "Python/bytecodes.c" + if (PyGen_Check(receiver) || PyCoro_CheckExact(receiver)) { + PyErr_SetObject(PyExc_StopIteration, value); + if (monitor_stop_iteration(tstate, frame, next_instr-1)) { + goto error; + } + PyErr_SetRaisedException(NULL); + } + Py_DECREF(receiver); + #line 322 "Python/generated_cases.c.h" + STACK_SHRINK(1); + stack_pointer[-1] = value; + DISPATCH(); + } + TARGET(UNARY_NEGATIVE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 187 "Python/bytecodes.c" + #line 250 "Python/bytecodes.c" res = PyNumber_Negative(value); - #line 247 "Python/generated_cases.c.h" + #line 333 "Python/generated_cases.c.h" Py_DECREF(value); - #line 189 "Python/bytecodes.c" + #line 252 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 251 "Python/generated_cases.c.h" + #line 337 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -255,11 +341,11 @@ TARGET(UNARY_NOT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 193 "Python/bytecodes.c" + #line 256 "Python/bytecodes.c" int err = PyObject_IsTrue(value); - #line 261 "Python/generated_cases.c.h" + #line 347 "Python/generated_cases.c.h" Py_DECREF(value); - #line 195 "Python/bytecodes.c" + #line 258 "Python/bytecodes.c" if (err < 0) goto pop_1_error; if (err == 0) { res = Py_True; @@ -268,7 +354,7 @@ res = Py_False; } Py_INCREF(res); - #line 272 "Python/generated_cases.c.h" + #line 358 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -276,13 +362,13 @@ TARGET(UNARY_INVERT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 206 "Python/bytecodes.c" + #line 269 "Python/bytecodes.c" res = PyNumber_Invert(value); - #line 282 "Python/generated_cases.c.h" + #line 368 "Python/generated_cases.c.h" Py_DECREF(value); - #line 208 "Python/bytecodes.c" + #line 271 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 286 "Python/generated_cases.c.h" + #line 372 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -291,8 +377,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *prod; - #line 225 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 288 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -300,7 +385,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (prod == NULL) goto pop_2_error; - #line 304 "Python/generated_cases.c.h" + #line 389 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = prod; next_instr += 1; @@ -311,15 +396,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *prod; - #line 236 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 298 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); double dprod = ((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dprod, prod); - #line 323 "Python/generated_cases.c.h" + #line 407 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = prod; next_instr += 1; @@ -330,8 +414,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sub; - #line 246 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 307 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -339,7 +422,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (sub == NULL) goto pop_2_error; - #line 343 "Python/generated_cases.c.h" + #line 426 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sub; next_instr += 1; @@ -350,14 +433,13 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sub; - #line 257 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 317 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); double dsub = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsub, sub); - #line 361 "Python/generated_cases.c.h" + #line 443 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sub; next_instr += 1; @@ -368,8 +450,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 266 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 325 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -377,7 +458,7 @@ _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (res == NULL) goto pop_2_error; - #line 381 "Python/generated_cases.c.h" + #line 462 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -387,8 +468,7 @@ TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 283 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 341 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP]; @@ -415,7 +495,7 @@ if (*target_local == NULL) goto pop_2_error; // The STORE_FAST is already done. JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); - #line 419 "Python/generated_cases.c.h" + #line 499 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -424,15 +504,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sum; - #line 313 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 370 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); STAT_INC(BINARY_OP, hit); double dsum = ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsum, sum); - #line 436 "Python/generated_cases.c.h" + #line 515 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sum; next_instr += 1; @@ -443,8 +522,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sum; - #line 323 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 379 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -452,7 +530,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (sum == NULL) goto pop_2_error; - #line 456 "Python/generated_cases.c.h" + #line 534 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sum; next_instr += 1; @@ -465,11 +543,10 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *res; - #line 342 "Python/bytecodes.c" + #line 397 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); next_instr--; _Py_Specialize_BinarySubscr(container, sub, next_instr); DISPATCH_SAME_OPARG(); @@ -478,12 +555,12 @@ DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ res = PyObject_GetItem(container, sub); - #line 482 "Python/generated_cases.c.h" + #line 559 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 355 "Python/bytecodes.c" + #line 409 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 487 "Python/generated_cases.c.h" + #line 564 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -495,7 +572,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; - #line 359 "Python/bytecodes.c" + #line 413 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -508,7 +585,7 @@ } Py_DECREF(container); if (res == NULL) goto pop_3_error; - #line 512 "Python/generated_cases.c.h" + #line 589 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = res; DISPATCH(); @@ -519,7 +596,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; - #line 374 "Python/bytecodes.c" + #line 428 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -532,7 +609,7 @@ Py_DECREF(v); Py_DECREF(container); if (err) goto pop_4_error; - #line 536 "Python/generated_cases.c.h" + #line 613 "Python/generated_cases.c.h" STACK_SHRINK(4); DISPATCH(); } @@ -541,8 +618,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; - #line 389 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 443 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -556,7 +632,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 560 "Python/generated_cases.c.h" + #line 636 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -567,8 +643,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; - #line 406 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 459 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -582,7 +657,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(tuple); - #line 586 "Python/generated_cases.c.h" + #line 661 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -593,8 +668,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; - #line 423 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 475 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); @@ -602,14 +676,14 @@ if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } - #line 606 "Python/generated_cases.c.h" + #line 680 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); - #line 432 "Python/bytecodes.c" + #line 483 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub - #line 613 "Python/generated_cases.c.h" + #line 687 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); STACK_SHRINK(1); @@ -621,7 +695,7 @@ TARGET(BINARY_SUBSCR_GETITEM) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 439 "Python/bytecodes.c" + #line 490 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; @@ -642,15 +716,15 @@ new_frame->localsplus[1] = sub; JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); DISPATCH_INLINED(new_frame); - #line 646 "Python/generated_cases.c.h" + #line 720 "Python/generated_cases.c.h" } TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 462 "Python/bytecodes.c" + #line 513 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; - #line 654 "Python/generated_cases.c.h" + #line 728 "Python/generated_cases.c.h" STACK_SHRINK(1); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -659,13 +733,13 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 467 "Python/bytecodes.c" + #line 518 "Python/bytecodes.c" int err = PySet_Add(set, v); - #line 665 "Python/generated_cases.c.h" + #line 739 "Python/generated_cases.c.h" Py_DECREF(v); - #line 469 "Python/bytecodes.c" + #line 520 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 669 "Python/generated_cases.c.h" + #line 743 "Python/generated_cases.c.h" STACK_SHRINK(1); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -678,10 +752,9 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 480 "Python/bytecodes.c" + #line 531 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { - assert(cframe.use_tracing == 0); next_instr--; _Py_Specialize_StoreSubscr(container, sub, next_instr); DISPATCH_SAME_OPARG(); @@ -694,13 +767,13 @@ #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); - #line 698 "Python/generated_cases.c.h" + #line 771 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - #line 496 "Python/bytecodes.c" + #line 546 "Python/bytecodes.c" if (err) goto pop_3_error; - #line 704 "Python/generated_cases.c.h" + #line 777 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -710,8 +783,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 500 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 550 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -728,7 +800,7 @@ Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 732 "Python/generated_cases.c.h" + #line 804 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -738,14 +810,13 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 520 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 569 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); Py_DECREF(dict); if (err) goto pop_3_error; - #line 749 "Python/generated_cases.c.h" + #line 820 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -754,15 +825,15 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 529 "Python/bytecodes.c" + #line 577 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); - #line 761 "Python/generated_cases.c.h" + #line 832 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 532 "Python/bytecodes.c" + #line 580 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 766 "Python/generated_cases.c.h" + #line 837 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -770,14 +841,14 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 536 "Python/bytecodes.c" + #line 584 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); - #line 777 "Python/generated_cases.c.h" + #line 848 "Python/generated_cases.c.h" Py_DECREF(value); - #line 539 "Python/bytecodes.c" + #line 587 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 781 "Python/generated_cases.c.h" + #line 852 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -786,15 +857,15 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 543 "Python/bytecodes.c" + #line 591 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); - #line 793 "Python/generated_cases.c.h" + #line 864 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 546 "Python/bytecodes.c" + #line 594 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 798 "Python/generated_cases.c.h" + #line 869 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -802,7 +873,7 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); - #line 550 "Python/bytecodes.c" + #line 598 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -820,34 +891,31 @@ break; } if (true) { STACK_SHRINK(oparg); goto error; } - #line 824 "Python/generated_cases.c.h" + #line 895 "Python/generated_cases.c.h" } TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; - #line 570 "Python/bytecodes.c" + #line 618 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); STACK_SHRINK(1); // Since we're not going to DISPATCH() assert(EMPTY()); /* Restore previous cframe and return. */ tstate->cframe = cframe.previous; - tstate->cframe->use_tracing = cframe.use_tracing; assert(tstate->cframe->current_frame == frame->previous); assert(!_PyErr_Occurred(tstate)); _Py_LeaveRecursiveCallTstate(tstate); return retval; - #line 841 "Python/generated_cases.c.h" + #line 911 "Python/generated_cases.c.h" } TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 584 "Python/bytecodes.c" + #line 631 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); - TRACE_FUNCTION_EXIT(); - DTRACE_FUNCTION_EXIT(); _Py_LeaveRecursiveCallPy(tstate); assert(frame != &entry_frame); // GH-99729: We need to unlink the frame *before* clearing it: @@ -856,17 +924,36 @@ _PyEvalFrameClearAndPop(tstate, dying); _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 860 "Python/generated_cases.c.h" + #line 928 "Python/generated_cases.c.h" + } + + TARGET(INSTRUMENTED_RETURN_VALUE) { + PyObject *retval = stack_pointer[-1]; + #line 645 "Python/bytecodes.c" + int err = _Py_call_instrumentation_arg( + tstate, PY_MONITORING_EVENT_PY_RETURN, + frame, next_instr-1, retval); + if (err) goto error; + STACK_SHRINK(1); + assert(EMPTY()); + _PyFrame_SetStackPointer(frame, stack_pointer); + _Py_LeaveRecursiveCallPy(tstate); + assert(frame != &entry_frame); + // GH-99729: We need to unlink the frame *before* clearing it: + _PyInterpreterFrame *dying = frame; + frame = cframe.current_frame = dying->previous; + _PyEvalFrameClearAndPop(tstate, dying); + _PyFrame_StackPush(frame, retval); + goto resume_frame; + #line 949 "Python/generated_cases.c.h" } TARGET(RETURN_CONST) { - #line 600 "Python/bytecodes.c" + #line 663 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); - TRACE_FUNCTION_EXIT(); - DTRACE_FUNCTION_EXIT(); _Py_LeaveRecursiveCallPy(tstate); assert(frame != &entry_frame); // GH-99729: We need to unlink the frame *before* clearing it: @@ -875,13 +962,34 @@ _PyEvalFrameClearAndPop(tstate, dying); _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 879 "Python/generated_cases.c.h" + #line 966 "Python/generated_cases.c.h" + } + + TARGET(INSTRUMENTED_RETURN_CONST) { + #line 678 "Python/bytecodes.c" + PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); + int err = _Py_call_instrumentation_arg( + tstate, PY_MONITORING_EVENT_PY_RETURN, + frame, next_instr-1, retval); + if (err) goto error; + Py_INCREF(retval); + assert(EMPTY()); + _PyFrame_SetStackPointer(frame, stack_pointer); + _Py_LeaveRecursiveCallPy(tstate); + assert(frame != &entry_frame); + // GH-99729: We need to unlink the frame *before* clearing it: + _PyInterpreterFrame *dying = frame; + frame = cframe.current_frame = dying->previous; + _PyEvalFrameClearAndPop(tstate, dying); + _PyFrame_StackPush(frame, retval); + goto resume_frame; + #line 987 "Python/generated_cases.c.h" } TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 617 "Python/bytecodes.c" + #line 697 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -894,16 +1002,16 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); - #line 898 "Python/generated_cases.c.h" + #line 1006 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 630 "Python/bytecodes.c" + #line 710 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); - #line 905 "Python/generated_cases.c.h" + #line 1013 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 635 "Python/bytecodes.c" + #line 715 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -916,7 +1024,7 @@ Py_DECREF(iter); if (true) goto pop_1_error; } - #line 920 "Python/generated_cases.c.h" + #line 1028 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -924,7 +1032,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 650 "Python/bytecodes.c" + #line 730 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -968,7 +1076,7 @@ } } - #line 972 "Python/generated_cases.c.h" + #line 1080 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; PREDICT(LOAD_CONST); @@ -979,16 +1087,16 @@ PREDICTED(GET_AWAITABLE); PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 697 "Python/bytecodes.c" + #line 777 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } - #line 990 "Python/generated_cases.c.h" + #line 1098 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 704 "Python/bytecodes.c" + #line 784 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1006,7 +1114,7 @@ if (iter == NULL) goto pop_1_error; - #line 1010 "Python/generated_cases.c.h" + #line 1118 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -1017,11 +1125,10 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 730 "Python/bytecodes.c" + #line 810 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); next_instr--; _Py_Specialize_Send(receiver, next_instr); DISPATCH_SAME_OPARG(); @@ -1030,6 +1137,20 @@ DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ assert(frame != &entry_frame); + if ((Py_TYPE(receiver) == &PyGen_Type || + Py_TYPE(receiver) == &PyCoro_Type) && ((PyGenObject *)receiver)->gi_frame_state < FRAME_EXECUTING) + { + PyGenObject *gen = (PyGenObject *)receiver; + _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; + frame->yield_offset = oparg; + STACK_SHRINK(1); + _PyFrame_StackPush(gen_frame, v); + gen->gi_frame_state = FRAME_EXECUTING; + gen->gi_exc_state.previous_item = tstate->exc_info; + tstate->exc_info = &gen->gi_exc_state; + JUMPBY(INLINE_CACHE_ENTRIES_SEND + oparg); + DISPATCH_INLINED(gen_frame); + } if (Py_IsNone(v) && PyIter_Check(receiver)) { retval = Py_TYPE(receiver)->tp_iternext(receiver); } @@ -1037,23 +1158,20 @@ retval = PyObject_CallMethodOneArg(receiver, &_Py_ID(send), v); } if (retval == NULL) { - if (tstate->c_tracefunc != NULL - && _PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) - call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame); + if (_PyErr_ExceptionMatches(tstate, PyExc_StopIteration) + ) { + monitor_raise(tstate, frame, next_instr-1); + } if (_PyGen_FetchStopIterationValue(&retval) == 0) { assert(retval != NULL); JUMPBY(oparg); } else { - assert(retval == NULL); goto error; } } - else { - assert(retval != NULL); - } Py_DECREF(v); - #line 1057 "Python/generated_cases.c.h" + #line 1175 "Python/generated_cases.c.h" stack_pointer[-1] = retval; next_instr += 1; DISPATCH(); @@ -1062,8 +1180,7 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 768 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 858 "Python/bytecodes.c" PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type, SEND); @@ -1078,12 +1195,35 @@ tstate->exc_info = &gen->gi_exc_state; JUMPBY(INLINE_CACHE_ENTRIES_SEND + oparg); DISPATCH_INLINED(gen_frame); - #line 1082 "Python/generated_cases.c.h" + #line 1199 "Python/generated_cases.c.h" + } + + TARGET(INSTRUMENTED_YIELD_VALUE) { + PyObject *retval = stack_pointer[-1]; + #line 875 "Python/bytecodes.c" + assert(frame != &entry_frame); + PyGenObject *gen = _PyFrame_GetGenerator(frame); + gen->gi_frame_state = FRAME_SUSPENDED; + _PyFrame_SetStackPointer(frame, stack_pointer - 1); + int err = _Py_call_instrumentation_arg( + tstate, PY_MONITORING_EVENT_PY_YIELD, + frame, next_instr-1, retval); + if (err) goto error; + tstate->exc_info = gen->gi_exc_state.previous_item; + gen->gi_exc_state.previous_item = NULL; + _Py_LeaveRecursiveCallPy(tstate); + _PyInterpreterFrame *gen_frame = frame; + frame = cframe.current_frame = frame->previous; + gen_frame->previous = NULL; + frame->prev_instr -= frame->yield_offset; + _PyFrame_StackPush(frame, retval); + goto resume_frame; + #line 1222 "Python/generated_cases.c.h" } TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 786 "Python/bytecodes.c" + #line 895 "Python/bytecodes.c" // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -1091,8 +1231,6 @@ PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_SUSPENDED; _PyFrame_SetStackPointer(frame, stack_pointer - 1); - TRACE_FUNCTION_EXIT(); - DTRACE_FUNCTION_EXIT(); tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; _Py_LeaveRecursiveCallPy(tstate); @@ -1102,15 +1240,15 @@ frame->prev_instr -= frame->yield_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1106 "Python/generated_cases.c.h" + #line 1244 "Python/generated_cases.c.h" } TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 807 "Python/bytecodes.c" + #line 914 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - #line 1114 "Python/generated_cases.c.h" + #line 1252 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1118,7 +1256,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 812 "Python/bytecodes.c" + #line 919 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1136,26 +1274,26 @@ Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; - #line 1140 "Python/generated_cases.c.h" + #line 1278 "Python/generated_cases.c.h" } TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 832 "Python/bytecodes.c" + #line 939 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { - #line 1149 "Python/generated_cases.c.h" + #line 1287 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 835 "Python/bytecodes.c" + #line 942 "Python/bytecodes.c" } else { Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } - #line 1159 "Python/generated_cases.c.h" + #line 1297 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -1166,23 +1304,23 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 844 "Python/bytecodes.c" + #line 951 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { value = Py_NewRef(((PyStopIterationObject *)exc_value)->value); - #line 1175 "Python/generated_cases.c.h" + #line 1313 "Python/generated_cases.c.h" Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 849 "Python/bytecodes.c" + #line 956 "Python/bytecodes.c" none = Py_NewRef(Py_None); } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); goto exception_unwind; } - #line 1186 "Python/generated_cases.c.h" + #line 1324 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; stack_pointer[-2] = none; @@ -1191,9 +1329,9 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 858 "Python/bytecodes.c" + #line 965 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 1197 "Python/generated_cases.c.h" + #line 1335 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1201,7 +1339,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 862 "Python/bytecodes.c" + #line 969 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1223,7 +1361,7 @@ if (true) goto error; } } - #line 1227 "Python/generated_cases.c.h" + #line 1365 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; DISPATCH(); @@ -1231,33 +1369,33 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 886 "Python/bytecodes.c" + #line 993 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); - #line 1242 "Python/generated_cases.c.h" + #line 1380 "Python/generated_cases.c.h" Py_DECREF(v); - #line 893 "Python/bytecodes.c" + #line 1000 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); - #line 1251 "Python/generated_cases.c.h" + #line 1389 "Python/generated_cases.c.h" Py_DECREF(v); - #line 900 "Python/bytecodes.c" + #line 1007 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1255 "Python/generated_cases.c.h" + #line 1393 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_NAME) { - #line 904 "Python/bytecodes.c" + #line 1011 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1274,7 +1412,7 @@ name); goto error; } - #line 1278 "Python/generated_cases.c.h" + #line 1416 "Python/generated_cases.c.h" DISPATCH(); } @@ -1282,11 +1420,10 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 930 "Python/bytecodes.c" + #line 1037 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); next_instr--; _Py_Specialize_UnpackSequence(seq, next_instr, oparg); DISPATCH_SAME_OPARG(); @@ -1296,11 +1433,11 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - #line 1300 "Python/generated_cases.c.h" + #line 1437 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 944 "Python/bytecodes.c" + #line 1050 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1304 "Python/generated_cases.c.h" + #line 1441 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; @@ -1310,14 +1447,14 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 948 "Python/bytecodes.c" + #line 1054 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - #line 1321 "Python/generated_cases.c.h" + #line 1458 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1328,7 +1465,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 958 "Python/bytecodes.c" + #line 1064 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1336,7 +1473,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1340 "Python/generated_cases.c.h" + #line 1477 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1347,7 +1484,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 969 "Python/bytecodes.c" + #line 1075 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1355,7 +1492,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1359 "Python/generated_cases.c.h" + #line 1496 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1365,15 +1502,15 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 980 "Python/bytecodes.c" + #line 1086 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - #line 1373 "Python/generated_cases.c.h" + #line 1510 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 984 "Python/bytecodes.c" + #line 1090 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1377 "Python/generated_cases.c.h" + #line 1514 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } @@ -1384,10 +1521,9 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 995 "Python/bytecodes.c" + #line 1101 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { - assert(cframe.use_tracing == 0); PyObject *name = GETITEM(frame->f_code->co_names, oparg); next_instr--; _Py_Specialize_StoreAttr(owner, next_instr, name); @@ -1401,12 +1537,12 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); - #line 1405 "Python/generated_cases.c.h" + #line 1541 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 1012 "Python/bytecodes.c" + #line 1117 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 1410 "Python/generated_cases.c.h" + #line 1546 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -1414,34 +1550,34 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 1016 "Python/bytecodes.c" + #line 1121 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - #line 1421 "Python/generated_cases.c.h" + #line 1557 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1019 "Python/bytecodes.c" + #line 1124 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1425 "Python/generated_cases.c.h" + #line 1561 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 1023 "Python/bytecodes.c" + #line 1128 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 1435 "Python/generated_cases.c.h" + #line 1571 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1026 "Python/bytecodes.c" + #line 1131 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1439 "Python/generated_cases.c.h" + #line 1575 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_GLOBAL) { - #line 1030 "Python/bytecodes.c" + #line 1135 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1453,13 +1589,13 @@ } goto error; } - #line 1457 "Python/generated_cases.c.h" + #line 1593 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_NAME) { PyObject *v; - #line 1044 "Python/bytecodes.c" + #line 1149 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *locals = LOCALS(); if (locals == NULL) { @@ -1518,7 +1654,7 @@ } } } - #line 1522 "Python/generated_cases.c.h" + #line 1658 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = v; DISPATCH(); @@ -1529,11 +1665,10 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1111 "Python/bytecodes.c" + #line 1216 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); next_instr--; _Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name); @@ -1582,7 +1717,7 @@ } } null = NULL; - #line 1586 "Python/generated_cases.c.h" + #line 1721 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1596,8 +1731,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1166 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 1270 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -1608,7 +1742,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1612 "Python/generated_cases.c.h" + #line 1746 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1623,12 +1757,12 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); - #line 1180 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 1283 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); PyDictObject *bdict = (PyDictObject *)BUILTINS(); + assert(opcode == LOAD_GLOBAL_BUILTIN); DEOPT_IF(mdict->ma_keys->dk_version != mod_version, LOAD_GLOBAL); DEOPT_IF(bdict->ma_keys->dk_version != bltn_version, LOAD_GLOBAL); assert(DK_IS_UNICODE(bdict->ma_keys)); @@ -1638,7 +1772,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1642 "Python/generated_cases.c.h" + #line 1776 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1648,16 +1782,16 @@ } TARGET(DELETE_FAST) { - #line 1197 "Python/bytecodes.c" + #line 1300 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1656 "Python/generated_cases.c.h" + #line 1790 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { - #line 1203 "Python/bytecodes.c" + #line 1306 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -1666,12 +1800,12 @@ goto resume_with_error; } SETLOCAL(oparg, cell); - #line 1670 "Python/generated_cases.c.h" + #line 1804 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { - #line 1214 "Python/bytecodes.c" + #line 1317 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1682,13 +1816,13 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1686 "Python/generated_cases.c.h" + #line 1820 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_CLASSDEREF) { PyObject *value; - #line 1227 "Python/bytecodes.c" + #line 1330 "Python/bytecodes.c" PyObject *name, *locals = LOCALS(); assert(locals); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); @@ -1720,7 +1854,7 @@ } Py_INCREF(value); } - #line 1724 "Python/generated_cases.c.h" + #line 1858 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1728,7 +1862,7 @@ TARGET(LOAD_DEREF) { PyObject *value; - #line 1261 "Python/bytecodes.c" + #line 1364 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1736,7 +1870,7 @@ if (true) goto error; } Py_INCREF(value); - #line 1740 "Python/generated_cases.c.h" + #line 1874 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1744,18 +1878,18 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1271 "Python/bytecodes.c" + #line 1374 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 1753 "Python/generated_cases.c.h" + #line 1887 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #line 1278 "Python/bytecodes.c" + #line 1381 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); @@ -1766,22 +1900,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 1770 "Python/generated_cases.c.h" + #line 1904 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1291 "Python/bytecodes.c" + #line 1394 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 1779 "Python/generated_cases.c.h" + #line 1913 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1293 "Python/bytecodes.c" + #line 1396 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1785 "Python/generated_cases.c.h" + #line 1919 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -1791,10 +1925,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1297 "Python/bytecodes.c" + #line 1400 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1798 "Python/generated_cases.c.h" + #line 1932 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -1804,10 +1938,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1302 "Python/bytecodes.c" + #line 1405 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1811 "Python/generated_cases.c.h" + #line 1945 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -1817,7 +1951,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1307 "Python/bytecodes.c" + #line 1410 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1828,13 +1962,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 1832 "Python/generated_cases.c.h" + #line 1966 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1318 "Python/bytecodes.c" + #line 1421 "Python/bytecodes.c" if (true) goto pop_1_error; } Py_DECREF(none_val); - #line 1838 "Python/generated_cases.c.h" + #line 1972 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -1843,13 +1977,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1325 "Python/bytecodes.c" + #line 1428 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 1849 "Python/generated_cases.c.h" + #line 1983 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1327 "Python/bytecodes.c" + #line 1430 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 1853 "Python/generated_cases.c.h" + #line 1987 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1857,7 +1991,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1331 "Python/bytecodes.c" + #line 1434 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -1872,7 +2006,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 1876 "Python/generated_cases.c.h" + #line 2010 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -1882,7 +2016,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1348 "Python/bytecodes.c" + #line 1451 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -1890,13 +2024,13 @@ if (map == NULL) goto error; - #line 1894 "Python/generated_cases.c.h" + #line 2028 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1356 "Python/bytecodes.c" + #line 1459 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 1900 "Python/generated_cases.c.h" + #line 2034 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -1904,7 +2038,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1360 "Python/bytecodes.c" + #line 1463 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -1944,7 +2078,7 @@ Py_DECREF(ann_dict); } } - #line 1948 "Python/generated_cases.c.h" + #line 2082 "Python/generated_cases.c.h" DISPATCH(); } @@ -1952,7 +2086,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1402 "Python/bytecodes.c" + #line 1505 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1962,14 +2096,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 1966 "Python/generated_cases.c.h" + #line 2100 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1412 "Python/bytecodes.c" + #line 1515 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 1973 "Python/generated_cases.c.h" + #line 2107 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -1977,7 +2111,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1416 "Python/bytecodes.c" + #line 1519 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -1985,12 +2119,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 1989 "Python/generated_cases.c.h" + #line 2123 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1424 "Python/bytecodes.c" + #line 1527 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 1994 "Python/generated_cases.c.h" + #line 2128 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -1998,17 +2132,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1430 "Python/bytecodes.c" + #line 1533 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 2007 "Python/generated_cases.c.h" + #line 2141 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1435 "Python/bytecodes.c" + #line 1538 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2012 "Python/generated_cases.c.h" + #line 2146 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); PREDICT(CALL_FUNCTION_EX); @@ -2018,13 +2152,13 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1442 "Python/bytecodes.c" + #line 1545 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 2028 "Python/generated_cases.c.h" + #line 2162 "Python/generated_cases.c.h" STACK_SHRINK(2); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -2036,11 +2170,10 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1465 "Python/bytecodes.c" + #line 1568 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); next_instr--; _Py_Specialize_LoadAttr(owner, next_instr, name); @@ -2071,9 +2204,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2075 "Python/generated_cases.c.h" + #line 2208 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1500 "Python/bytecodes.c" + #line 1602 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2082,12 +2215,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2086 "Python/generated_cases.c.h" + #line 2219 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1509 "Python/bytecodes.c" + #line 1611 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2091 "Python/generated_cases.c.h" + #line 2224 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2101,8 +2234,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1514 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 1616 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2115,7 +2247,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2119 "Python/generated_cases.c.h" + #line 2251 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2130,8 +2262,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1531 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 1632 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2144,7 +2275,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2148 "Python/generated_cases.c.h" + #line 2279 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2159,8 +2290,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1548 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 1648 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2187,7 +2317,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2191 "Python/generated_cases.c.h" + #line 2321 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2202,8 +2332,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1579 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 1678 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2213,7 +2342,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2217 "Python/generated_cases.c.h" + #line 2346 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2228,8 +2357,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1593 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 1691 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2241,7 +2369,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2245 "Python/generated_cases.c.h" + #line 2373 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2255,8 +2383,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1609 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 1706 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2279,7 +2406,7 @@ new_frame->localsplus[0] = owner; JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); DISPATCH_INLINED(new_frame); - #line 2283 "Python/generated_cases.c.h" + #line 2410 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2287,8 +2414,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1635 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 1731 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2313,7 +2439,7 @@ new_frame->localsplus[1] = Py_NewRef(name); JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); DISPATCH_INLINED(new_frame); - #line 2317 "Python/generated_cases.c.h" + #line 2443 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2321,8 +2447,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1663 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 1758 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2340,7 +2465,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2344 "Python/generated_cases.c.h" + #line 2469 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2351,8 +2476,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1684 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 1778 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2391,7 +2515,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2395 "Python/generated_cases.c.h" + #line 2519 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2402,8 +2526,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1726 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 1819 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2413,7 +2536,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2417 "Python/generated_cases.c.h" + #line 2540 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2425,11 +2548,10 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1746 "Python/bytecodes.c" + #line 1838 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); next_instr--; _Py_Specialize_CompareOp(left, right, next_instr, oparg); DISPATCH_SAME_OPARG(); @@ -2439,12 +2561,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2443 "Python/generated_cases.c.h" + #line 2565 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1760 "Python/bytecodes.c" + #line 1851 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2448 "Python/generated_cases.c.h" + #line 2570 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2455,8 +2577,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1764 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 1855 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2468,7 +2589,7 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2472 "Python/generated_cases.c.h" + #line 2593 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2479,8 +2600,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1780 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 1870 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2496,7 +2616,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2500 "Python/generated_cases.c.h" + #line 2620 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2507,8 +2627,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1800 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 1889 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2521,7 +2640,7 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2525 "Python/generated_cases.c.h" + #line 2644 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2532,14 +2651,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1816 "Python/bytecodes.c" + #line 1904 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2538 "Python/generated_cases.c.h" + #line 2657 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1818 "Python/bytecodes.c" + #line 1906 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2543 "Python/generated_cases.c.h" + #line 2662 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2549,15 +2668,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1822 "Python/bytecodes.c" + #line 1910 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2555 "Python/generated_cases.c.h" + #line 2674 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1824 "Python/bytecodes.c" + #line 1912 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = Py_NewRef((res^oparg) ? Py_True : Py_False); - #line 2561 "Python/generated_cases.c.h" + #line 2680 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2568,12 +2687,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 1829 "Python/bytecodes.c" + #line 1917 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2574 "Python/generated_cases.c.h" + #line 2693 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1831 "Python/bytecodes.c" + #line 1919 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2581,10 +2700,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2585 "Python/generated_cases.c.h" + #line 2704 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1839 "Python/bytecodes.c" + #line 1927 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2593,7 +2712,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 2597 "Python/generated_cases.c.h" + #line 2716 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2603,21 +2722,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1850 "Python/bytecodes.c" + #line 1938 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2610 "Python/generated_cases.c.h" + #line 2729 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1853 "Python/bytecodes.c" + #line 1941 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 2617 "Python/generated_cases.c.h" + #line 2736 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1858 "Python/bytecodes.c" + #line 1946 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2621 "Python/generated_cases.c.h" + #line 2740 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -2626,15 +2745,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 1862 "Python/bytecodes.c" + #line 1950 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 2633 "Python/generated_cases.c.h" + #line 2752 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 1865 "Python/bytecodes.c" + #line 1953 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2638 "Python/generated_cases.c.h" + #line 2757 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -2643,29 +2762,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 1869 "Python/bytecodes.c" + #line 1957 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 2651 "Python/generated_cases.c.h" + #line 2770 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 1875 "Python/bytecodes.c" + #line 1963 "Python/bytecodes.c" JUMPBY(oparg); - #line 2660 "Python/generated_cases.c.h" + #line 2779 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 1879 "Python/bytecodes.c" + #line 1967 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 2669 "Python/generated_cases.c.h" + #line 2788 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -2673,7 +2792,7 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 1885 "Python/bytecodes.c" + #line 1973 "Python/bytecodes.c" if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2683,9 +2802,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2687 "Python/generated_cases.c.h" + #line 2806 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 1895 "Python/bytecodes.c" + #line 1983 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -2693,14 +2812,14 @@ if (err < 0) goto pop_1_error; } } - #line 2697 "Python/generated_cases.c.h" + #line 2816 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 1905 "Python/bytecodes.c" + #line 1993 "Python/bytecodes.c" if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2710,9 +2829,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2714 "Python/generated_cases.c.h" + #line 2833 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 1915 "Python/bytecodes.c" + #line 2003 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -2720,67 +2839,67 @@ if (err < 0) goto pop_1_error; } } - #line 2724 "Python/generated_cases.c.h" + #line 2843 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 1925 "Python/bytecodes.c" + #line 2013 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 2733 "Python/generated_cases.c.h" + #line 2852 "Python/generated_cases.c.h" Py_DECREF(value); - #line 1927 "Python/bytecodes.c" + #line 2015 "Python/bytecodes.c" JUMPBY(oparg); } else { _Py_DECREF_NO_DEALLOC(value); } - #line 2741 "Python/generated_cases.c.h" + #line 2860 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 1935 "Python/bytecodes.c" + #line 2023 "Python/bytecodes.c" if (Py_IsNone(value)) { _Py_DECREF_NO_DEALLOC(value); JUMPBY(oparg); } else { - #line 2754 "Python/generated_cases.c.h" + #line 2873 "Python/generated_cases.c.h" Py_DECREF(value); - #line 1941 "Python/bytecodes.c" + #line 2029 "Python/bytecodes.c" } - #line 2758 "Python/generated_cases.c.h" + #line 2877 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 1945 "Python/bytecodes.c" + #line 2033 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 2771 "Python/generated_cases.c.h" + #line 2890 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 1954 "Python/bytecodes.c" + #line 2042 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 2784 "Python/generated_cases.c.h" + #line 2903 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -2791,16 +2910,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 1962 "Python/bytecodes.c" + #line 2050 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 2800 "Python/generated_cases.c.h" + #line 2919 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 1967 "Python/bytecodes.c" + #line 2055 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -2808,7 +2927,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_NewRef(Py_None); // Failure! } - #line 2812 "Python/generated_cases.c.h" + #line 2931 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -2817,10 +2936,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 1977 "Python/bytecodes.c" + #line 2065 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); - #line 2824 "Python/generated_cases.c.h" + #line 2943 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -2830,10 +2949,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 1983 "Python/bytecodes.c" + #line 2071 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); - #line 2837 "Python/generated_cases.c.h" + #line 2956 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -2844,11 +2963,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 1989 "Python/bytecodes.c" + #line 2077 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 2852 "Python/generated_cases.c.h" + #line 2971 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -2857,14 +2976,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 1995 "Python/bytecodes.c" + #line 2083 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 2864 "Python/generated_cases.c.h" + #line 2983 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1998 "Python/bytecodes.c" + #line 2086 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 2868 "Python/generated_cases.c.h" + #line 2987 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -2872,7 +2991,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2002 "Python/bytecodes.c" + #line 2090 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -2895,11 +3014,11 @@ if (iter == NULL) { goto error; } - #line 2899 "Python/generated_cases.c.h" + #line 3018 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2025 "Python/bytecodes.c" + #line 2113 "Python/bytecodes.c" } - #line 2903 "Python/generated_cases.c.h" + #line 3022 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -2910,11 +3029,10 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2044 "Python/bytecodes.c" + #line 2132 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); next_instr--; _Py_Specialize_ForIter(iter, next_instr, oparg); DISPATCH_SAME_OPARG(); @@ -2929,13 +3047,12 @@ if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { goto error; } - else if (tstate->c_tracefunc != NULL) { - call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame); - } + monitor_raise(tstate, frame, next_instr-1); _PyErr_Clear(tstate); } /* iterator ended normally */ - assert(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == END_FOR); + assert(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == END_FOR || + next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == INSTRUMENTED_END_FOR); Py_DECREF(iter); STACK_SHRINK(1); /* Jump forward oparg, then skip following END_FOR instruction */ @@ -2943,18 +3060,48 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 2947 "Python/generated_cases.c.h" + #line 3064 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; DISPATCH(); } + TARGET(INSTRUMENTED_FOR_ITER) { + #line 2165 "Python/bytecodes.c" + _Py_CODEUNIT *here = next_instr-1; + _Py_CODEUNIT *target; + PyObject *iter = TOP(); + PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); + if (next != NULL) { + PUSH(next); + target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER; + } + else { + if (_PyErr_Occurred(tstate)) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { + goto error; + } + monitor_raise(tstate, frame, here); + _PyErr_Clear(tstate); + } + /* iterator ended normally */ + assert(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == END_FOR || + next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == INSTRUMENTED_END_FOR); + STACK_SHRINK(1); + Py_DECREF(iter); + /* Skip END_FOR */ + target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; + } + INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); + #line 3098 "Python/generated_cases.c.h" + DISPATCH(); + } + TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2079 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 2193 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -2974,7 +3121,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 2978 "Python/generated_cases.c.h" + #line 3125 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -2984,8 +3131,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2102 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 2215 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3005,7 +3151,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3009 "Python/generated_cases.c.h" + #line 3155 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3015,8 +3161,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2125 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 2237 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3034,7 +3179,7 @@ if (next == NULL) { goto error; } - #line 3038 "Python/generated_cases.c.h" + #line 3183 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3043,8 +3188,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2146 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 2257 "Python/bytecodes.c" PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER); @@ -3056,16 +3200,17 @@ gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg); - assert(next_instr->op.code == END_FOR); + assert(next_instr->op.code == END_FOR || + next_instr->op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3062 "Python/generated_cases.c.h" + #line 3207 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2163 "Python/bytecodes.c" + #line 2274 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3088,16 +3233,16 @@ Py_DECREF(enter); goto error; } - #line 3092 "Python/generated_cases.c.h" + #line 3237 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2186 "Python/bytecodes.c" + #line 2297 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3101 "Python/generated_cases.c.h" + #line 3246 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3109,7 +3254,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2196 "Python/bytecodes.c" + #line 2307 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3135,16 +3280,16 @@ Py_DECREF(enter); goto error; } - #line 3139 "Python/generated_cases.c.h" + #line 3284 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2222 "Python/bytecodes.c" + #line 2333 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3148 "Python/generated_cases.c.h" + #line 3293 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3156,7 +3301,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2231 "Python/bytecodes.c" + #line 2342 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3177,7 +3322,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3181 "Python/generated_cases.c.h" + #line 3326 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3186,7 +3331,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2254 "Python/bytecodes.c" + #line 2365 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3196,7 +3341,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3200 "Python/generated_cases.c.h" + #line 3345 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3210,9 +3355,8 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2266 "Python/bytecodes.c" + #line 2377 "Python/bytecodes.c" /* Cached method object */ - assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3228,7 +3372,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3232 "Python/generated_cases.c.h" + #line 3376 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3242,8 +3386,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2286 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 2396 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3253,7 +3396,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3257 "Python/generated_cases.c.h" + #line 3400 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3267,8 +3410,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2299 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 2408 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3282,7 +3424,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3286 "Python/generated_cases.c.h" + #line 3428 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3291,14 +3433,31 @@ } TARGET(KW_NAMES) { - #line 2316 "Python/bytecodes.c" + #line 2424 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); - #line 3299 "Python/generated_cases.c.h" + #line 3441 "Python/generated_cases.c.h" DISPATCH(); } + TARGET(INSTRUMENTED_CALL) { + #line 2430 "Python/bytecodes.c" + int is_meth = PEEK(oparg+2) != NULL; + int total_args = oparg + is_meth; + PyObject *function = PEEK(total_args + 1); + PyObject *arg = total_args == 0 ? + &_PyInstrumentation_MISSING : PEEK(total_args); + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_CALL, + frame, next_instr-1, function, arg); + if (err) goto error; + _PyCallCache *cache = (_PyCallCache *)next_instr; + INCREMENT_ADAPTIVE_COUNTER(cache->counter); + GO_TO_INSTRUCTION(CALL); + #line 3459 "Python/generated_cases.c.h" + } + TARGET(CALL) { PREDICTED(CALL); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); @@ -3306,7 +3465,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2352 "Python/bytecodes.c" + #line 2475 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3317,7 +3476,6 @@ #if ENABLE_SPECIALIZATION _PyCallCache *cache = (_PyCallCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); next_instr--; _Py_Specialize_Call(callable, next_instr, total_args, kwnames); DISPATCH_SAME_OPARG(); @@ -3360,16 +3518,26 @@ DISPATCH_INLINED(new_frame); } /* Callable is not a normal Python function */ - if (cframe.use_tracing) { - res = trace_call_function( - tstate, callable, args, - positional_args, kwnames); - } - else { - res = PyObject_Vectorcall( - callable, args, - positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, - kwnames); + res = PyObject_Vectorcall( + callable, args, + positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, + kwnames); + if (opcode == INSTRUMENTED_CALL) { + PyObject *arg = total_args == 0 ? + &_PyInstrumentation_MISSING : PEEK(total_args); + if (res == NULL) { + _Py_call_instrumentation_exc2( + tstate, PY_MONITORING_EVENT_C_RAISE, + frame, next_instr-1, callable, arg); + } + else { + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_C_RETURN, + frame, next_instr-1, callable, arg); + if (err < 0) { + Py_CLEAR(res); + } + } } kwnames = NULL; assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); @@ -3378,7 +3546,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3382 "Python/generated_cases.c.h" + #line 3550 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3390,7 +3558,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2430 "Python/bytecodes.c" + #line 2562 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3400,7 +3568,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3404 "Python/generated_cases.c.h" + #line 3572 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3409,7 +3577,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2442 "Python/bytecodes.c" + #line 2574 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3434,7 +3602,7 @@ STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); DISPATCH_INLINED(new_frame); - #line 3438 "Python/generated_cases.c.h" + #line 3606 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3442,7 +3610,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2469 "Python/bytecodes.c" + #line 2601 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3477,7 +3645,7 @@ STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); DISPATCH_INLINED(new_frame); - #line 3481 "Python/generated_cases.c.h" + #line 3649 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3485,9 +3653,8 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2506 "Python/bytecodes.c" + #line 2638 "Python/bytecodes.c" assert(kwnames == NULL); - assert(cframe.use_tracing == 0); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); PyObject *obj = args[0]; @@ -3496,7 +3663,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3500 "Python/generated_cases.c.h" + #line 3667 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3509,9 +3676,8 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2519 "Python/bytecodes.c" + #line 2650 "Python/bytecodes.c" assert(kwnames == NULL); - assert(cframe.use_tracing == 0); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL); @@ -3521,7 +3687,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3525 "Python/generated_cases.c.h" + #line 3691 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3535,7 +3701,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2534 "Python/bytecodes.c" + #line 2664 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3546,7 +3712,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3550 "Python/generated_cases.c.h" + #line 3716 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3560,7 +3726,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2548 "Python/bytecodes.c" + #line 2678 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3582,7 +3748,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3586 "Python/generated_cases.c.h" + #line 3752 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3596,8 +3762,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2573 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 2703 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -3625,7 +3790,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3629 "Python/generated_cases.c.h" + #line 3794 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3639,8 +3804,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2605 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 2734 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -3672,7 +3836,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 3676 "Python/generated_cases.c.h" + #line 3840 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3686,8 +3850,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2641 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 2769 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -3719,7 +3882,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3723 "Python/generated_cases.c.h" + #line 3886 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3733,8 +3896,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2677 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 2804 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -3759,7 +3921,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3763 "Python/generated_cases.c.h" + #line 3925 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3772,8 +3934,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2705 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 2831 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -3800,7 +3961,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3804 "Python/generated_cases.c.h" + #line 3965 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3812,8 +3973,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2736 "Python/bytecodes.c" - assert(cframe.use_tracing == 0); + #line 2861 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -3831,14 +3991,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 3835 "Python/generated_cases.c.h" + #line 3995 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2757 "Python/bytecodes.c" + #line 2881 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -3869,7 +4029,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3873 "Python/generated_cases.c.h" + #line 4033 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3882,7 +4042,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2791 "Python/bytecodes.c" + #line 2915 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3911,7 +4071,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3915 "Python/generated_cases.c.h" + #line 4075 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3924,7 +4084,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2823 "Python/bytecodes.c" + #line 2947 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -3953,7 +4113,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3957 "Python/generated_cases.c.h" + #line 4117 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3966,7 +4126,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2855 "Python/bytecodes.c" + #line 2979 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -3994,7 +4154,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3998 "Python/generated_cases.c.h" + #line 4158 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4003,18 +4163,22 @@ DISPATCH(); } + TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { + #line 3010 "Python/bytecodes.c" + GO_TO_INSTRUCTION(CALL_FUNCTION_EX); + #line 4170 "Python/generated_cases.c.h" + } + TARGET(CALL_FUNCTION_EX) { PREDICTED(CALL_FUNCTION_EX); PyObject *kwargs = (oparg & 1) ? stack_pointer[-(((oparg & 1) ? 1 : 0))] : NULL; PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 2886 "Python/bytecodes.c" - if (oparg & 1) { - // DICT_MERGE is called before this opcode if there are kwargs. - // It converts all dict subtypes in kwargs into regular dicts. - assert(PyDict_CheckExact(kwargs)); - } + #line 3014 "Python/bytecodes.c" + // DICT_MERGE is called before this opcode if there are kwargs. + // It converts all dict subtypes in kwargs into regular dicts. + assert(kwargs == NULL || PyDict_CheckExact(kwargs)); if (!PyTuple_CheckExact(callargs)) { if (check_args_iterable(tstate, func, callargs) < 0) { goto error; @@ -4026,17 +4190,42 @@ Py_SETREF(callargs, tuple); } assert(PyTuple_CheckExact(callargs)); - - result = do_call_core(tstate, func, callargs, kwargs, cframe.use_tracing); - #line 4032 "Python/generated_cases.c.h" + EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func); + if (opcode == INSTRUMENTED_CALL_FUNCTION_EX && + !PyFunction_Check(func) && !PyMethod_Check(func) + ) { + PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ? + PyTuple_GET_ITEM(callargs, 0) : Py_None; + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_CALL, + frame, next_instr-1, func, arg); + if (err) goto error; + result = PyObject_Call(func, callargs, kwargs); + if (result == NULL) { + _Py_call_instrumentation_exc2( + tstate, PY_MONITORING_EVENT_C_RAISE, + frame, next_instr-1, func, arg); + } + else { + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_C_RETURN, + frame, next_instr-1, func, arg); + if (err < 0) { + Py_CLEAR(result); + } + } + } + else { + result = PyObject_Call(func, callargs, kwargs); + } + #line 4222 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 2905 "Python/bytecodes.c" - + #line 3057 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4040 "Python/generated_cases.c.h" + #line 4229 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4051,7 +4240,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; - #line 2916 "Python/bytecodes.c" + #line 3067 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4080,14 +4269,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4084 "Python/generated_cases.c.h" + #line 4273 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 2947 "Python/bytecodes.c" + #line 3098 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4108,7 +4297,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4112 "Python/generated_cases.c.h" + #line 4301 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4116,15 +4305,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 2970 "Python/bytecodes.c" + #line 3121 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4122 "Python/generated_cases.c.h" + #line 4311 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 2972 "Python/bytecodes.c" + #line 3123 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4128 "Python/generated_cases.c.h" + #line 4317 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4135,7 +4324,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 2976 "Python/bytecodes.c" + #line 3127 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4170,7 +4359,7 @@ Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4174 "Python/generated_cases.c.h" + #line 4363 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4179,10 +4368,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3013 "Python/bytecodes.c" + #line 3164 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4186 "Python/generated_cases.c.h" + #line 4375 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4194,11 +4383,10 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3018 "Python/bytecodes.c" + #line 3169 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); next_instr--; _Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, &GETLOCAL(0)); DISPATCH_SAME_OPARG(); @@ -4210,12 +4398,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4214 "Python/generated_cases.c.h" + #line 4402 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3034 "Python/bytecodes.c" + #line 3184 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4219 "Python/generated_cases.c.h" + #line 4407 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4225,27 +4413,153 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3039 "Python/bytecodes.c" + #line 3189 "Python/bytecodes.c" assert(oparg >= 2); - #line 4231 "Python/generated_cases.c.h" + #line 4419 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } + TARGET(INSTRUMENTED_LINE) { + #line 3193 "Python/bytecodes.c" + _Py_CODEUNIT *here = next_instr-1; + _PyFrame_SetStackPointer(frame, stack_pointer); + int original_opcode = _Py_call_instrumentation_line( + tstate, frame, here); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (original_opcode < 0) { + next_instr = here+1; + goto error; + } + next_instr = frame->prev_instr; + if (next_instr != here) { + DISPATCH(); + } + if (_PyOpcode_Caches[original_opcode]) { + _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1); + INCREMENT_ADAPTIVE_COUNTER(cache->counter); + } + opcode = original_opcode; + DISPATCH_GOTO(); + #line 4446 "Python/generated_cases.c.h" + } + + TARGET(INSTRUMENTED_INSTRUCTION) { + #line 3215 "Python/bytecodes.c" + int next_opcode = _Py_call_instrumentation_instruction( + tstate, frame, next_instr-1); + if (next_opcode < 0) goto error; + next_instr--; + if (_PyOpcode_Caches[next_opcode]) { + _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1); + INCREMENT_ADAPTIVE_COUNTER(cache->counter); + } + assert(next_opcode > 0 && next_opcode < 256); + opcode = next_opcode; + DISPATCH_GOTO(); + #line 4462 "Python/generated_cases.c.h" + } + + TARGET(INSTRUMENTED_JUMP_FORWARD) { + #line 3229 "Python/bytecodes.c" + INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); + #line 4468 "Python/generated_cases.c.h" + DISPATCH(); + } + + TARGET(INSTRUMENTED_JUMP_BACKWARD) { + #line 3233 "Python/bytecodes.c" + INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); + #line 4475 "Python/generated_cases.c.h" + CHECK_EVAL_BREAKER(); + DISPATCH(); + } + + TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { + #line 3238 "Python/bytecodes.c" + PyObject *cond = POP(); + int err = PyObject_IsTrue(cond); + Py_DECREF(cond); + if (err < 0) goto error; + _Py_CODEUNIT *here = next_instr-1; + assert(err == 0 || err == 1); + int offset = err*oparg; + INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); + #line 4490 "Python/generated_cases.c.h" + DISPATCH(); + } + + TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { + #line 3249 "Python/bytecodes.c" + PyObject *cond = POP(); + int err = PyObject_IsTrue(cond); + Py_DECREF(cond); + if (err < 0) goto error; + _Py_CODEUNIT *here = next_instr-1; + assert(err == 0 || err == 1); + int offset = (1-err)*oparg; + INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); + #line 4504 "Python/generated_cases.c.h" + DISPATCH(); + } + + TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { + #line 3260 "Python/bytecodes.c" + PyObject *value = POP(); + _Py_CODEUNIT *here = next_instr-1; + int offset; + if (Py_IsNone(value)) { + _Py_DECREF_NO_DEALLOC(value); + offset = oparg; + } + else { + Py_DECREF(value); + offset = 0; + } + INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); + #line 4522 "Python/generated_cases.c.h" + DISPATCH(); + } + + TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { + #line 3275 "Python/bytecodes.c" + PyObject *value = POP(); + _Py_CODEUNIT *here = next_instr-1; + int offset; + if (Py_IsNone(value)) { + _Py_DECREF_NO_DEALLOC(value); + offset = 0; + } + else { + Py_DECREF(value); + offset = oparg; + } + INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); + #line 4540 "Python/generated_cases.c.h" + DISPATCH(); + } + TARGET(EXTENDED_ARG) { - #line 3043 "Python/bytecodes.c" + #line 3290 "Python/bytecodes.c" assert(oparg); - assert(cframe.use_tracing == 0); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4245 "Python/generated_cases.c.h" + #line 4551 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3052 "Python/bytecodes.c" + #line 3298 "Python/bytecodes.c" + assert(0 && "Executing a cache."); + Py_UNREACHABLE(); + #line 4558 "Python/generated_cases.c.h" + } + + TARGET(RESERVED) { + #line 3303 "Python/bytecodes.c" + assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4251 "Python/generated_cases.c.h" + #line 4565 "Python/generated_cases.c.h" } diff --git a/Python/instrumentation.c b/Python/instrumentation.c new file mode 100644 index 000000000000..39a7eaa3bd2d --- /dev/null +++ b/Python/instrumentation.c @@ -0,0 +1,2021 @@ + + +#include "Python.h" +#include "pycore_call.h" +#include "pycore_frame.h" +#include "pycore_interp.h" +#include "pycore_long.h" +#include "pycore_namespace.h" +#include "pycore_object.h" +#include "pycore_opcode.h" +#include "pycore_pyerrors.h" +#include "pycore_pystate.h" + +/* Uncomment this to dump debugging output when assertions fail */ +// #define INSTRUMENT_DEBUG 1 + +static PyObject DISABLE = +{ + _PyObject_IMMORTAL_REFCNT, + &PyBaseObject_Type +}; + +PyObject _PyInstrumentation_MISSING = +{ + _PyObject_IMMORTAL_REFCNT, + &PyBaseObject_Type +}; + +static const int8_t EVENT_FOR_OPCODE[256] = { + [RETURN_CONST] = PY_MONITORING_EVENT_PY_RETURN, + [INSTRUMENTED_RETURN_CONST] = PY_MONITORING_EVENT_PY_RETURN, + [RETURN_VALUE] = PY_MONITORING_EVENT_PY_RETURN, + [INSTRUMENTED_RETURN_VALUE] = PY_MONITORING_EVENT_PY_RETURN, + [CALL] = PY_MONITORING_EVENT_CALL, + [INSTRUMENTED_CALL] = PY_MONITORING_EVENT_CALL, + [CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL, + [INSTRUMENTED_CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL, + [RESUME] = -1, + [YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD, + [INSTRUMENTED_YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD, + [JUMP_FORWARD] = PY_MONITORING_EVENT_JUMP, + [JUMP_BACKWARD] = PY_MONITORING_EVENT_JUMP, + [POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH, + [POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH, + [POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH, + [POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH, + [INSTRUMENTED_JUMP_FORWARD] = PY_MONITORING_EVENT_JUMP, + [INSTRUMENTED_JUMP_BACKWARD] = PY_MONITORING_EVENT_JUMP, + [INSTRUMENTED_POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH, + [INSTRUMENTED_POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH, + [INSTRUMENTED_POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH, + [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH, + [FOR_ITER] = PY_MONITORING_EVENT_BRANCH, + [INSTRUMENTED_FOR_ITER] = PY_MONITORING_EVENT_BRANCH, + [END_FOR] = PY_MONITORING_EVENT_STOP_ITERATION, + [INSTRUMENTED_END_FOR] = PY_MONITORING_EVENT_STOP_ITERATION, + [END_SEND] = PY_MONITORING_EVENT_STOP_ITERATION, + [INSTRUMENTED_END_SEND] = PY_MONITORING_EVENT_STOP_ITERATION, +}; + +static const uint8_t DE_INSTRUMENT[256] = { + [INSTRUMENTED_RESUME] = RESUME, + [INSTRUMENTED_RETURN_VALUE] = RETURN_VALUE, + [INSTRUMENTED_RETURN_CONST] = RETURN_CONST, + [INSTRUMENTED_CALL] = CALL, + [INSTRUMENTED_CALL_FUNCTION_EX] = CALL_FUNCTION_EX, + [INSTRUMENTED_YIELD_VALUE] = YIELD_VALUE, + [INSTRUMENTED_JUMP_FORWARD] = JUMP_FORWARD, + [INSTRUMENTED_JUMP_BACKWARD] = JUMP_BACKWARD, + [INSTRUMENTED_POP_JUMP_IF_FALSE] = POP_JUMP_IF_FALSE, + [INSTRUMENTED_POP_JUMP_IF_TRUE] = POP_JUMP_IF_TRUE, + [INSTRUMENTED_POP_JUMP_IF_NONE] = POP_JUMP_IF_NONE, + [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = POP_JUMP_IF_NOT_NONE, + [INSTRUMENTED_FOR_ITER] = FOR_ITER, + [INSTRUMENTED_END_FOR] = END_FOR, + [INSTRUMENTED_END_SEND] = END_SEND, +}; + +static const uint8_t INSTRUMENTED_OPCODES[256] = { + [RETURN_CONST] = INSTRUMENTED_RETURN_CONST, + [INSTRUMENTED_RETURN_CONST] = INSTRUMENTED_RETURN_CONST, + [RETURN_VALUE] = INSTRUMENTED_RETURN_VALUE, + [INSTRUMENTED_RETURN_VALUE] = INSTRUMENTED_RETURN_VALUE, + [CALL] = INSTRUMENTED_CALL, + [INSTRUMENTED_CALL] = INSTRUMENTED_CALL, + [CALL_FUNCTION_EX] = INSTRUMENTED_CALL_FUNCTION_EX, + [INSTRUMENTED_CALL_FUNCTION_EX] = INSTRUMENTED_CALL_FUNCTION_EX, + [YIELD_VALUE] = INSTRUMENTED_YIELD_VALUE, + [INSTRUMENTED_YIELD_VALUE] = INSTRUMENTED_YIELD_VALUE, + [RESUME] = INSTRUMENTED_RESUME, + [INSTRUMENTED_RESUME] = INSTRUMENTED_RESUME, + [JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD, + [INSTRUMENTED_JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD, + [JUMP_BACKWARD] = INSTRUMENTED_JUMP_BACKWARD, + [INSTRUMENTED_JUMP_BACKWARD] = INSTRUMENTED_JUMP_BACKWARD, + [POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE, + [INSTRUMENTED_POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE, + [POP_JUMP_IF_TRUE] = INSTRUMENTED_POP_JUMP_IF_TRUE, + [INSTRUMENTED_POP_JUMP_IF_TRUE] = INSTRUMENTED_POP_JUMP_IF_TRUE, + [POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE, + [INSTRUMENTED_POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE, + [POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE, + [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE, + [END_FOR] = INSTRUMENTED_END_FOR, + [INSTRUMENTED_END_FOR] = INSTRUMENTED_END_FOR, + [END_SEND] = INSTRUMENTED_END_SEND, + [INSTRUMENTED_END_SEND] = INSTRUMENTED_END_SEND, + + [INSTRUMENTED_LINE] = INSTRUMENTED_LINE, + [INSTRUMENTED_INSTRUCTION] = INSTRUMENTED_INSTRUCTION, +}; + +static inline bool +opcode_has_event(int opcode) { + return opcode < INSTRUMENTED_LINE && + INSTRUMENTED_OPCODES[opcode] > 0; +} + +static inline bool +is_instrumented(int opcode) { + assert(opcode != 0); + assert(opcode != RESERVED); + return opcode >= MIN_INSTRUMENTED_OPCODE; +} + +static inline bool +monitors_equals(_Py_Monitors a, _Py_Monitors b) +{ + for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { + if (a.tools[i] != b.tools[i]) { + return false; + } + } + return true; +} + +static inline _Py_Monitors +monitors_sub(_Py_Monitors a, _Py_Monitors b) +{ + _Py_Monitors res; + for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { + res.tools[i] = a.tools[i] & ~b.tools[i]; + } + return res; +} + +static inline _Py_Monitors +monitors_and(_Py_Monitors a, _Py_Monitors b) +{ + _Py_Monitors res; + for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { + res.tools[i] = a.tools[i] & b.tools[i]; + } + return res; +} + +static inline _Py_Monitors +monitors_or(_Py_Monitors a, _Py_Monitors b) +{ + _Py_Monitors res; + for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { + res.tools[i] = a.tools[i] | b.tools[i]; + } + return res; +} + +static inline bool +monitors_are_empty(_Py_Monitors m) +{ + for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { + if (m.tools[i]) { + return false; + } + } + return true; +} + +static inline bool +multiple_tools(_Py_Monitors *m) +{ + for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { + if (_Py_popcount32(m->tools[i]) > 1) { + return true; + } + } + return false; +} + +static inline _PyMonitoringEventSet +get_events(_Py_Monitors *m, int tool_id) +{ + _PyMonitoringEventSet result = 0; + for (int e = 0; e < PY_MONITORING_UNGROUPED_EVENTS; e++) { + if ((m->tools[e] >> tool_id) & 1) { + result |= (1 << e); + } + } + return result; +} + +/* Line delta. + * 8 bit value. + * if line_delta == -128: + * line = None # represented as -1 + * elif line_delta == -127: + * line = PyCode_Addr2Line(code, offset * sizeof(_Py_CODEUNIT)); + * else: + * line = first_line + (offset >> OFFSET_SHIFT) + line_delta; + */ + +#define NO_LINE -128 +#define COMPUTED_LINE -127 + +#define OFFSET_SHIFT 4 + +static int8_t +compute_line_delta(PyCodeObject *code, int offset, int line) +{ + if (line < 0) { + return NO_LINE; + } + int delta = line - code->co_firstlineno - (offset >> OFFSET_SHIFT); + if (delta <= INT8_MAX && delta > COMPUTED_LINE) { + return delta; + } + return COMPUTED_LINE; +} + +static int +compute_line(PyCodeObject *code, int offset, int8_t line_delta) +{ + if (line_delta > COMPUTED_LINE) { + return code->co_firstlineno + (offset >> OFFSET_SHIFT) + line_delta; + } + if (line_delta == NO_LINE) { + + return -1; + } + assert(line_delta == COMPUTED_LINE); + /* Look it up */ + return PyCode_Addr2Line(code, offset * sizeof(_Py_CODEUNIT)); +} + +static int +instruction_length(PyCodeObject *code, int offset) +{ + int opcode = _PyCode_CODE(code)[offset].op.code; + assert(opcode != 0); + assert(opcode != RESERVED); + if (opcode == INSTRUMENTED_LINE) { + opcode = code->_co_monitoring->lines[offset].original_opcode; + } + if (opcode == INSTRUMENTED_INSTRUCTION) { + opcode = code->_co_monitoring->per_instruction_opcodes[offset]; + } + int deinstrumented = DE_INSTRUMENT[opcode]; + if (deinstrumented) { + opcode = deinstrumented; + } + else { + opcode = _PyOpcode_Deopt[opcode]; + } + assert(opcode != 0); + assert(!is_instrumented(opcode)); + assert(opcode == _PyOpcode_Deopt[opcode]); + return 1 + _PyOpcode_Caches[opcode]; +} + +#ifdef INSTRUMENT_DEBUG + +static void +dump_instrumentation_data_tools(PyCodeObject *code, uint8_t *tools, int i, FILE*out) +{ + if (tools == NULL) { + fprintf(out, "tools = NULL"); + } + else { + fprintf(out, "tools = %d", tools[i]); + } +} + +static void +dump_instrumentation_data_lines(PyCodeObject *code, _PyCoLineInstrumentationData *lines, int i, FILE*out) +{ + if (lines == NULL) { + fprintf(out, ", lines = NULL"); + } + else if (lines[i].original_opcode == 0) { + fprintf(out, ", lines = {original_opcode = No LINE (0), line_delta = %d)", lines[i].line_delta); + } + else { + fprintf(out, ", lines = {original_opcode = %s, line_delta = %d)", _PyOpcode_OpName[lines[i].original_opcode], lines[i].line_delta); + } +} + +static void +dump_instrumentation_data_line_tools(PyCodeObject *code, uint8_t *line_tools, int i, FILE*out) +{ + if (line_tools == NULL) { + fprintf(out, ", line_tools = NULL"); + } + else { + fprintf(out, ", line_tools = %d", line_tools[i]); + } +} + +static void +dump_instrumentation_data_per_instruction(PyCodeObject *code, _PyCoMonitoringData *data, int i, FILE*out) +{ + if (data->per_instruction_opcodes == NULL) { + fprintf(out, ", per-inst opcode = NULL"); + } + else { + fprintf(out, ", per-inst opcode = %s", _PyOpcode_OpName[data->per_instruction_opcodes[i]]); + } + if (data->per_instruction_tools == NULL) { + fprintf(out, ", per-inst tools = NULL"); + } + else { + fprintf(out, ", per-inst tools = %d", data->per_instruction_tools[i]); + } +} + +static void +dump_monitors(const char *prefix, _Py_Monitors monitors, FILE*out) +{ + fprintf(out, "%s monitors:\n", prefix); + for (int event = 0; event < PY_MONITORING_UNGROUPED_EVENTS; event++) { + fprintf(out, " Event %d: Tools %x\n", event, monitors.tools[event]); + } +} + +/* Like _Py_GetBaseOpcode but without asserts. + * Does its best to give the right answer, but won't abort + * if something is wrong */ +int get_base_opcode_best_attempt(PyCodeObject *code, int offset) +{ + int opcode = _Py_OPCODE(_PyCode_CODE(code)[offset]); + if (INSTRUMENTED_OPCODES[opcode] != opcode) { + /* Not instrumented */ + return _PyOpcode_Deopt[opcode] == 0 ? opcode : _PyOpcode_Deopt[opcode]; + } + if (opcode == INSTRUMENTED_INSTRUCTION) { + if (code->_co_monitoring->per_instruction_opcodes[offset] == 0) { + return opcode; + } + opcode = code->_co_monitoring->per_instruction_opcodes[offset]; + } + if (opcode == INSTRUMENTED_LINE) { + if (code->_co_monitoring->lines[offset].original_opcode == 0) { + return opcode; + } + opcode = code->_co_monitoring->lines[offset].original_opcode; + } + int deinstrumented = DE_INSTRUMENT[opcode]; + if (deinstrumented) { + return deinstrumented; + } + if (_PyOpcode_Deopt[opcode] == 0) { + return opcode; + } + return _PyOpcode_Deopt[opcode]; +} + +/* No error checking -- Don't use this for anything but experimental debugging */ +static void +dump_instrumentation_data(PyCodeObject *code, int star, FILE*out) +{ + _PyCoMonitoringData *data = code->_co_monitoring; + fprintf(out, "\n"); + PyObject_Print(code->co_name, out, Py_PRINT_RAW); + fprintf(out, "\n"); + if (data == NULL) { + fprintf(out, "NULL\n"); + return; + } + dump_monitors("Global", PyInterpreterState_Get()->monitors, out); + dump_monitors("Code", data->local_monitors, out); + dump_monitors("Active", data->active_monitors, out); + int code_len = (int)Py_SIZE(code); + bool starred = false; + for (int i = 0; i < code_len; i += instruction_length(code, i)) { + _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; + int opcode = instr->op.code; + if (i == star) { + fprintf(out, "** "); + starred = true; + } + fprintf(out, "Offset: %d, line: %d %s: ", i, PyCode_Addr2Line(code, i*2), _PyOpcode_OpName[opcode]); + dump_instrumentation_data_tools(code, data->tools, i, out); + dump_instrumentation_data_lines(code, data->lines, i, out); + dump_instrumentation_data_line_tools(code, data->line_tools, i, out); + dump_instrumentation_data_per_instruction(code, data, i, out); + fprintf(out, "\n"); + ; + } + if (!starred && star >= 0) { + fprintf(out, "Error offset not at valid instruction offset: %d\n", star); + fprintf(out, " "); + dump_instrumentation_data_tools(code, data->tools, star, out); + dump_instrumentation_data_lines(code, data->lines, star, out); + dump_instrumentation_data_line_tools(code, data->line_tools, star, out); + dump_instrumentation_data_per_instruction(code, data, star, out); + fprintf(out, "\n"); + } +} + +#define CHECK(test) do { \ + if (!(test)) { \ + dump_instrumentation_data(code, i, stderr); \ + } \ + assert(test); \ +} while (0) + +bool valid_opcode(int opcode) { + if (opcode > 0 && + opcode != RESERVED && + opcode < 255 && + _PyOpcode_OpName[opcode] && + _PyOpcode_OpName[opcode][0] != '<' + ) { + return true; + } + return false; +} + +static void +sanity_check_instrumentation(PyCodeObject *code) +{ + _PyCoMonitoringData *data = code->_co_monitoring; + if (data == NULL) { + return; + } + _Py_Monitors active_monitors = PyInterpreterState_Get()->monitors; + if (code->_co_monitoring) { + _Py_Monitors local_monitors = code->_co_monitoring->local_monitors; + active_monitors = monitors_or(active_monitors, local_monitors); + } + assert(monitors_equals( + code->_co_monitoring->active_monitors, + active_monitors) + ); + int code_len = (int)Py_SIZE(code); + for (int i = 0; i < code_len;) { + int opcode = _PyCode_CODE(code)[i].op.code; + int base_opcode = _Py_GetBaseOpcode(code, i); + CHECK(valid_opcode(opcode)); + CHECK(valid_opcode(base_opcode)); + if (opcode == INSTRUMENTED_INSTRUCTION) { + opcode = data->per_instruction_opcodes[i]; + if (!is_instrumented(opcode)) { + CHECK(_PyOpcode_Deopt[opcode] == opcode); + } + if (data->per_instruction_tools) { + uint8_t tools = active_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION]; + CHECK((tools & data->per_instruction_tools[i]) == data->per_instruction_tools[i]); + } + } + if (opcode == INSTRUMENTED_LINE) { + CHECK(data->lines); + CHECK(valid_opcode(data->lines[i].original_opcode)); + opcode = data->lines[i].original_opcode; + CHECK(opcode != END_FOR); + CHECK(opcode != RESUME); + CHECK(opcode != INSTRUMENTED_RESUME); + if (!is_instrumented(opcode)) { + CHECK(_PyOpcode_Deopt[opcode] == opcode); + } + CHECK(opcode != INSTRUMENTED_LINE); + } + else if (data->lines && !is_instrumented(opcode)) { + CHECK(data->lines[i].original_opcode == 0 || + data->lines[i].original_opcode == base_opcode || + DE_INSTRUMENT[data->lines[i].original_opcode] == base_opcode); + } + if (is_instrumented(opcode)) { + CHECK(DE_INSTRUMENT[opcode] == base_opcode); + int event = EVENT_FOR_OPCODE[DE_INSTRUMENT[opcode]]; + if (event < 0) { + /* RESUME fixup */ + event = _PyCode_CODE(code)[i].op.arg; + } + CHECK(active_monitors.tools[event] != 0); + } + if (data->lines && base_opcode != END_FOR) { + int line1 = compute_line(code, i, data->lines[i].line_delta); + int line2 = PyCode_Addr2Line(code, i*sizeof(_Py_CODEUNIT)); + CHECK(line1 == line2); + } + CHECK(valid_opcode(opcode)); + if (data->tools) { + uint8_t local_tools = data->tools[i]; + if (opcode_has_event(base_opcode)) { + int event = EVENT_FOR_OPCODE[base_opcode]; + if (event == -1) { + /* RESUME fixup */ + event = _PyCode_CODE(code)[i].op.arg; + } + CHECK((active_monitors.tools[event] & local_tools) == local_tools); + } + else { + CHECK(local_tools == 0xff); + } + } + i += instruction_length(code, i); + assert(i <= code_len); + } +} +#else + +#define CHECK(test) assert(test) + +#endif + +/* Get the underlying opcode, stripping instrumentation */ +int _Py_GetBaseOpcode(PyCodeObject *code, int i) +{ + int opcode = _PyCode_CODE(code)[i].op.code; + if (opcode == INSTRUMENTED_LINE) { + opcode = code->_co_monitoring->lines[i].original_opcode; + } + if (opcode == INSTRUMENTED_INSTRUCTION) { + opcode = code->_co_monitoring->per_instruction_opcodes[i]; + } + CHECK(opcode != INSTRUMENTED_INSTRUCTION); + CHECK(opcode != INSTRUMENTED_LINE); + int deinstrumented = DE_INSTRUMENT[opcode]; + if (deinstrumented) { + return deinstrumented; + } + return _PyOpcode_Deopt[opcode]; +} + +static void +de_instrument(PyCodeObject *code, int i, int event) +{ + assert(event != PY_MONITORING_EVENT_INSTRUCTION); + assert(event != PY_MONITORING_EVENT_LINE); + + _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; + uint8_t *opcode_ptr = &instr->op.code; + int opcode = *opcode_ptr; + if (opcode == INSTRUMENTED_LINE) { + opcode_ptr = &code->_co_monitoring->lines[i].original_opcode; + opcode = *opcode_ptr; + } + if (opcode == INSTRUMENTED_INSTRUCTION) { + opcode_ptr = &code->_co_monitoring->per_instruction_opcodes[i]; + opcode = *opcode_ptr; + } + int deinstrumented = DE_INSTRUMENT[opcode]; + if (deinstrumented == 0) { + return; + } + CHECK(_PyOpcode_Deopt[deinstrumented] == deinstrumented); + *opcode_ptr = deinstrumented; + if (_PyOpcode_Caches[deinstrumented]) { + instr[1].cache = adaptive_counter_warmup(); + } +} + +static void +de_instrument_line(PyCodeObject *code, int i) +{ + _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; + uint8_t *opcode_ptr = &instr->op.code; + int opcode =*opcode_ptr; + if (opcode != INSTRUMENTED_LINE) { + return; + } + _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i]; + int original_opcode = lines->original_opcode; + CHECK(original_opcode != 0); + CHECK(original_opcode == _PyOpcode_Deopt[original_opcode]); + *opcode_ptr = instr->op.code = original_opcode; + if (_PyOpcode_Caches[original_opcode]) { + instr[1].cache = adaptive_counter_warmup(); + } + assert(*opcode_ptr != INSTRUMENTED_LINE); + assert(instr->op.code != INSTRUMENTED_LINE); +} + + +static void +de_instrument_per_instruction(PyCodeObject *code, int i) +{ + _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; + uint8_t *opcode_ptr = &instr->op.code; + int opcode =*opcode_ptr; + if (opcode == INSTRUMENTED_LINE) { + opcode_ptr = &code->_co_monitoring->lines[i].original_opcode; + opcode = *opcode_ptr; + } + if (opcode != INSTRUMENTED_INSTRUCTION) { + return; + } + int original_opcode = code->_co_monitoring->per_instruction_opcodes[i]; + CHECK(original_opcode != 0); + CHECK(original_opcode == _PyOpcode_Deopt[original_opcode]); + instr->op.code = original_opcode; + if (_PyOpcode_Caches[original_opcode]) { + instr[1].cache = adaptive_counter_warmup(); + } + assert(instr->op.code != INSTRUMENTED_INSTRUCTION); + /* Keep things clean for sanity check */ + code->_co_monitoring->per_instruction_opcodes[i] = 0; +} + + +static void +instrument(PyCodeObject *code, int i) +{ + _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; + uint8_t *opcode_ptr = &instr->op.code; + int opcode =*opcode_ptr; + if (opcode == INSTRUMENTED_LINE) { + _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i]; + opcode_ptr = &lines->original_opcode; + opcode = *opcode_ptr; + } + if (opcode == INSTRUMENTED_INSTRUCTION) { + opcode_ptr = &code->_co_monitoring->per_instruction_opcodes[i]; + opcode = *opcode_ptr; + CHECK(!is_instrumented(opcode)); + CHECK(opcode == _PyOpcode_Deopt[opcode]); + } + CHECK(opcode != 0); + if (!is_instrumented(opcode)) { + int deopt = _PyOpcode_Deopt[opcode]; + int instrumented = INSTRUMENTED_OPCODES[deopt]; + assert(instrumented); + *opcode_ptr = instrumented; + if (_PyOpcode_Caches[deopt]) { + instr[1].cache = adaptive_counter_warmup(); + } + } +} + +static void +instrument_line(PyCodeObject *code, int i) +{ + uint8_t *opcode_ptr = &_PyCode_CODE(code)[i].op.code; + int opcode =*opcode_ptr; + if (opcode == INSTRUMENTED_LINE) { + return; + } + _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i]; + lines->original_opcode = _PyOpcode_Deopt[opcode]; + CHECK(lines->original_opcode > 0); + *opcode_ptr = INSTRUMENTED_LINE; +} + +static void +instrument_per_instruction(PyCodeObject *code, int i) +{ + _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; + uint8_t *opcode_ptr = &instr->op.code; + int opcode =*opcode_ptr; + if (opcode == INSTRUMENTED_LINE) { + _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i]; + opcode_ptr = &lines->original_opcode; + opcode = *opcode_ptr; + } + if (opcode == INSTRUMENTED_INSTRUCTION) { + return; + } + CHECK(opcode != 0); + if (is_instrumented(opcode)) { + code->_co_monitoring->per_instruction_opcodes[i] = opcode; + } + else { + assert(opcode != 0); + assert(_PyOpcode_Deopt[opcode] != 0); + assert(_PyOpcode_Deopt[opcode] != RESUME); + code->_co_monitoring->per_instruction_opcodes[i] = _PyOpcode_Deopt[opcode]; + } + assert(code->_co_monitoring->per_instruction_opcodes[i] > 0); + *opcode_ptr = INSTRUMENTED_INSTRUCTION; +} + +#ifndef NDEBUG +static bool +instruction_has_event(PyCodeObject *code, int offset) +{ + _Py_CODEUNIT instr = _PyCode_CODE(code)[offset]; + int opcode = instr.op.code; + if (opcode == INSTRUMENTED_LINE) { + opcode = code->_co_monitoring->lines[offset].original_opcode; + } + if (opcode == INSTRUMENTED_INSTRUCTION) { + opcode = code->_co_monitoring->per_instruction_opcodes[offset]; + } + return opcode_has_event(opcode); +} +#endif + +static void +remove_tools(PyCodeObject * code, int offset, int event, int tools) +{ + assert(event != PY_MONITORING_EVENT_LINE); + assert(event != PY_MONITORING_EVENT_INSTRUCTION); + assert(event < PY_MONITORING_INSTRUMENTED_EVENTS); + assert(instruction_has_event(code, offset)); + _PyCoMonitoringData *monitoring = code->_co_monitoring; + if (monitoring && monitoring->tools) { + monitoring->tools[offset] &= ~tools; + if (monitoring->tools[offset] == 0) { + de_instrument(code, offset, event); + } + } + else { + /* Single tool */ + uint8_t single_tool = code->_co_monitoring->active_monitors.tools[event]; + assert(_Py_popcount32(single_tool) <= 1); + if (((single_tool & tools) == single_tool)) { + de_instrument(code, offset, event); + } + } +} + +#ifndef NDEBUG +static bool +tools_is_subset_for_event(PyCodeObject * code, int event, int tools) +{ + int global_tools = PyInterpreterState_Get()->monitors.tools[event]; + int local_tools = code->_co_monitoring->local_monitors.tools[event]; + return tools == ((global_tools | local_tools) & tools); +} +#endif + +static void +remove_line_tools(PyCodeObject * code, int offset, int tools) +{ + assert(code->_co_monitoring); + if (code->_co_monitoring->line_tools) + { + uint8_t *toolsptr = &code->_co_monitoring->line_tools[offset]; + *toolsptr &= ~tools; + if (*toolsptr == 0 ) { + de_instrument_line(code, offset); + } + } + else { + /* Single tool */ + uint8_t single_tool = code->_co_monitoring->active_monitors.tools[PY_MONITORING_EVENT_LINE]; + assert(_Py_popcount32(single_tool) <= 1); + if (((single_tool & tools) == single_tool)) { + de_instrument_line(code, offset); + } + } +} + +static void +add_tools(PyCodeObject * code, int offset, int event, int tools) +{ + assert(event != PY_MONITORING_EVENT_LINE); + assert(event != PY_MONITORING_EVENT_INSTRUCTION); + assert(event < PY_MONITORING_INSTRUMENTED_EVENTS); + assert(code->_co_monitoring); + if (code->_co_monitoring && + code->_co_monitoring->tools + ) { + code->_co_monitoring->tools[offset] |= tools; + } + else { + /* Single tool */ + assert(_Py_popcount32(tools) == 1); + assert(tools_is_subset_for_event(code, event, tools)); + } + instrument(code, offset); +} + +static void +add_line_tools(PyCodeObject * code, int offset, int tools) +{ + assert(tools_is_subset_for_event(code, PY_MONITORING_EVENT_LINE, tools)); + assert(code->_co_monitoring); + if (code->_co_monitoring->line_tools + ) { + code->_co_monitoring->line_tools[offset] |= tools; + } + else { + /* Single tool */ + assert(_Py_popcount32(tools) == 1); + } + instrument_line(code, offset); +} + + +static void +add_per_instruction_tools(PyCodeObject * code, int offset, int tools) +{ + assert(tools_is_subset_for_event(code, PY_MONITORING_EVENT_INSTRUCTION, tools)); + assert(code->_co_monitoring); + if (code->_co_monitoring->per_instruction_tools + ) { + code->_co_monitoring->per_instruction_tools[offset] |= tools; + } + else { + /* Single tool */ + assert(_Py_popcount32(tools) == 1); + } + instrument_per_instruction(code, offset); +} + + +static void +remove_per_instruction_tools(PyCodeObject * code, int offset, int tools) +{ + assert(code->_co_monitoring); + if (code->_co_monitoring->per_instruction_tools) + { + uint8_t *toolsptr = &code->_co_monitoring->per_instruction_tools[offset]; + *toolsptr &= ~tools; + if (*toolsptr == 0 ) { + de_instrument_per_instruction(code, offset); + } + } + else { + /* Single tool */ + uint8_t single_tool = code->_co_monitoring->active_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION]; + assert(_Py_popcount32(single_tool) <= 1); + if (((single_tool & tools) == single_tool)) { + de_instrument_per_instruction(code, offset); + } + } +} + + +/* Return 1 if DISABLE returned, -1 if error, 0 otherwise */ +static int +call_one_instrument( + PyInterpreterState *interp, PyThreadState *tstate, PyObject **args, + Py_ssize_t nargsf, int8_t tool, int event) +{ + assert(0 <= tool && tool < 8); + assert(tstate->tracing == 0); + PyObject *instrument = interp->monitoring_callables[tool][event]; + if (instrument == NULL) { + return 0; + } + int old_what = tstate->what_event; + tstate->what_event = event; + tstate->tracing++; + PyObject *res = _PyObject_VectorcallTstate(tstate, instrument, args, nargsf, NULL); + tstate->tracing--; + tstate->what_event = old_what; + if (res == NULL) { + return -1; + } + Py_DECREF(res); + return (res == &DISABLE); +} + +static const int8_t MOST_SIGNIFICANT_BITS[16] = { + -1, 0, 1, 1, + 2, 2, 2, 2, + 3, 3, 3, 3, + 3, 3, 3, 3, +}; + +/* We could use _Py_bit_length here, but that is designed for larger (32/64) bit ints, + and can perform relatively poorly on platforms without the necessary intrinsics. */ +static inline int most_significant_bit(uint8_t bits) { + assert(bits != 0); + if (bits > 15) { + return MOST_SIGNIFICANT_BITS[bits>>4]+4; + } + else { + return MOST_SIGNIFICANT_BITS[bits]; + } +} + +static bool +is_version_up_to_date(PyCodeObject *code, PyInterpreterState *interp) +{ + return interp->monitoring_version == code->_co_instrumentation_version; +} + +#ifndef NDEBUG +static bool +instrumentation_cross_checks(PyInterpreterState *interp, PyCodeObject *code) +{ + _Py_Monitors expected = monitors_or( + interp->monitors, + code->_co_monitoring->local_monitors); + return monitors_equals(code->_co_monitoring->active_monitors, expected); +} +#endif + +static inline uint8_t +get_tools_for_instruction(PyCodeObject * code, int i, int event) +{ + uint8_t tools; + assert(event != PY_MONITORING_EVENT_LINE); + assert(event != PY_MONITORING_EVENT_INSTRUCTION); + assert(instrumentation_cross_checks(PyThreadState_GET()->interp, code)); + _PyCoMonitoringData *monitoring = code->_co_monitoring; + if (event >= PY_MONITORING_UNGROUPED_EVENTS) { + assert(event == PY_MONITORING_EVENT_C_RAISE || + event == PY_MONITORING_EVENT_C_RETURN); + event = PY_MONITORING_EVENT_CALL; + } + if (event < PY_MONITORING_INSTRUMENTED_EVENTS && monitoring->tools) { + tools = monitoring->tools[i]; + } + else { + tools = code->_co_monitoring->active_monitors.tools[event]; + } + CHECK(tools_is_subset_for_event(code, event, tools)); + CHECK((tools & code->_co_monitoring->active_monitors.tools[event]) == tools); + return tools; +} + +static int +call_instrumentation_vector( + PyThreadState *tstate, int event, + _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, Py_ssize_t nargs, PyObject *args[]) +{ + if (tstate->tracing) { + return 0; + } + assert(!_PyErr_Occurred(tstate)); + assert(args[0] == NULL); + PyCodeObject *code = frame->f_code; + assert(code->_co_instrumentation_version == tstate->interp->monitoring_version); + assert(is_version_up_to_date(code, tstate->interp)); + assert(instrumentation_cross_checks(tstate->interp, code)); + assert(args[1] == NULL); + args[1] = (PyObject *)code; + int offset = (int)(instr - _PyCode_CODE(code)); + /* Offset visible to user should be the offset in bytes, as that is the + * convention for APIs involving code offsets. */ + int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT); + PyObject *offset_obj = PyLong_FromSsize_t(bytes_offset); + if (offset_obj == NULL) { + return -1; + } + assert(args[2] == NULL); + args[2] = offset_obj; + uint8_t tools = get_tools_for_instruction(code, offset, event); + Py_ssize_t nargsf = nargs | PY_VECTORCALL_ARGUMENTS_OFFSET; + PyObject **callargs = &args[1]; + int err = 0; + PyInterpreterState *interp = tstate->interp; + while (tools) { + int tool = most_significant_bit(tools); + assert(tool >= 0 && tool < 8); + assert(tools & (1 << tool)); + tools ^= (1 << tool); + int res = call_one_instrument(interp, tstate, callargs, nargsf, tool, event); + if (res == 0) { + /* Nothing to do */ + } + else if (res < 0) { + /* error */ + err = -1; + break; + } + else { + /* DISABLE */ + remove_tools(code, offset, event, 1 << tool); + } + } + Py_DECREF(offset_obj); + return err; +} + +int +_Py_call_instrumentation( + PyThreadState *tstate, int event, + _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) +{ + PyObject *args[3] = { NULL, NULL, NULL }; + return call_instrumentation_vector(tstate, event, frame, instr, 2, args); +} + +int +_Py_call_instrumentation_arg( + PyThreadState *tstate, int event, + _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg) +{ + PyObject *args[4] = { NULL, NULL, NULL, arg }; + return call_instrumentation_vector(tstate, event, frame, instr, 3, args); +} + +int +_Py_call_instrumentation_2args( + PyThreadState *tstate, int event, + _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1) +{ + PyObject *args[5] = { NULL, NULL, NULL, arg0, arg1 }; + return call_instrumentation_vector(tstate, event, frame, instr, 4, args); +} + +int +_Py_call_instrumentation_jump( + PyThreadState *tstate, int event, + _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *target +) { + assert(event == PY_MONITORING_EVENT_JUMP || + event == PY_MONITORING_EVENT_BRANCH); + assert(frame->prev_instr == instr); + frame->prev_instr = target; + PyCodeObject *code = frame->f_code; + int to = (int)(target - _PyCode_CODE(code)); + PyObject *to_obj = PyLong_FromLong(to * (int)sizeof(_Py_CODEUNIT)); + if (to_obj == NULL) { + return -1; + } + PyObject *args[4] = { NULL, NULL, NULL, to_obj }; + int err = call_instrumentation_vector(tstate, event, frame, instr, 3, args); + Py_DECREF(to_obj); + return err; +} + +static void +call_instrumentation_vector_protected( + PyThreadState *tstate, int event, + _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, Py_ssize_t nargs, PyObject *args[]) +{ + assert(_PyErr_Occurred(tstate)); + PyObject *exc = _PyErr_GetRaisedException(tstate); + int err = call_instrumentation_vector(tstate, event, frame, instr, nargs, args); + if (err) { + Py_XDECREF(exc); + } + else { + _PyErr_SetRaisedException(tstate, exc); + } + assert(_PyErr_Occurred(tstate)); +} + +void +_Py_call_instrumentation_exc0( + PyThreadState *tstate, int event, + _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) +{ + assert(_PyErr_Occurred(tstate)); + PyObject *args[3] = { NULL, NULL, NULL }; + call_instrumentation_vector_protected(tstate, event, frame, instr, 2, args); +} + +void +_Py_call_instrumentation_exc2( + PyThreadState *tstate, int event, + _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1) +{ + assert(_PyErr_Occurred(tstate)); + PyObject *args[5] = { NULL, NULL, NULL, arg0, arg1 }; + call_instrumentation_vector_protected(tstate, event, frame, instr, 4, args); +} + + +int +_Py_Instrumentation_GetLine(PyCodeObject *code, int index) +{ + _PyCoMonitoringData *monitoring = code->_co_monitoring; + assert(monitoring != NULL); + assert(monitoring->lines != NULL); + assert(index >= code->_co_firsttraceable); + assert(index < Py_SIZE(code)); + _PyCoLineInstrumentationData *line_data = &monitoring->lines[index]; + int8_t line_delta = line_data->line_delta; + int line = compute_line(code, index, line_delta); + return line; +} + +int +_Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr) +{ + frame->prev_instr = instr; + PyCodeObject *code = frame->f_code; + assert(is_version_up_to_date(code, tstate->interp)); + assert(instrumentation_cross_checks(tstate->interp, code)); + int i = (int)(instr - _PyCode_CODE(code)); + _PyCoMonitoringData *monitoring = code->_co_monitoring; + _PyCoLineInstrumentationData *line_data = &monitoring->lines[i]; + uint8_t original_opcode = line_data->original_opcode; + if (tstate->tracing) { + goto done; + } + PyInterpreterState *interp = tstate->interp; + int8_t line_delta = line_data->line_delta; + int line = compute_line(code, i, line_delta); + uint8_t tools = code->_co_monitoring->line_tools != NULL ? + code->_co_monitoring->line_tools[i] : + (interp->monitors.tools[PY_MONITORING_EVENT_LINE] | + code->_co_monitoring->local_monitors.tools[PY_MONITORING_EVENT_LINE] + ); + PyObject *line_obj = PyLong_FromSsize_t(line); + if (line_obj == NULL) { + return -1; + } + PyObject *args[3] = { NULL, (PyObject *)code, line_obj }; + while (tools) { + int tool = most_significant_bit(tools); + assert(tool >= 0 && tool < 8); + assert(tools & (1 << tool)); + tools &= ~(1 << tool); + int res = call_one_instrument(interp, tstate, &args[1], + 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, + tool, PY_MONITORING_EVENT_LINE); + if (res == 0) { + /* Nothing to do */ + } + else if (res < 0) { + /* error */ + Py_DECREF(line_obj); + return -1; + } + else { + /* DISABLE */ + remove_line_tools(code, i, 1 << tool); + } + } + Py_DECREF(line_obj); +done: + assert(original_opcode != 0); + assert(original_opcode < INSTRUMENTED_LINE); + assert(_PyOpcode_Deopt[original_opcode] == original_opcode); + return original_opcode; +} + +int +_Py_call_instrumentation_instruction(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr) +{ + PyCodeObject *code = frame->f_code; + assert(is_version_up_to_date(code, tstate->interp)); + assert(instrumentation_cross_checks(tstate->interp, code)); + int offset = (int)(instr - _PyCode_CODE(code)); + _PyCoMonitoringData *instrumentation_data = code->_co_monitoring; + assert(instrumentation_data->per_instruction_opcodes); + int next_opcode = instrumentation_data->per_instruction_opcodes[offset]; + if (tstate->tracing) { + return next_opcode; + } + PyInterpreterState *interp = tstate->interp; + uint8_t tools = instrumentation_data->per_instruction_tools != NULL ? + instrumentation_data->per_instruction_tools[offset] : + (interp->monitors.tools[PY_MONITORING_EVENT_INSTRUCTION] | + code->_co_monitoring->local_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION] + ); + int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT); + PyObject *offset_obj = PyLong_FromSsize_t(bytes_offset); + if (offset_obj == NULL) { + return -1; + } + PyObject *args[3] = { NULL, (PyObject *)code, offset_obj }; + while (tools) { + int tool = most_significant_bit(tools); + assert(tool >= 0 && tool < 8); + assert(tools & (1 << tool)); + tools &= ~(1 << tool); + int res = call_one_instrument(interp, tstate, &args[1], + 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, + tool, PY_MONITORING_EVENT_INSTRUCTION); + if (res == 0) { + /* Nothing to do */ + } + else if (res < 0) { + /* error */ + Py_DECREF(offset_obj); + return -1; + } + else { + /* DISABLE */ + remove_per_instruction_tools(code, offset, 1 << tool); + } + } + Py_DECREF(offset_obj); + assert(next_opcode != 0); + return next_opcode; +} + + +PyObject * +_PyMonitoring_RegisterCallback(int tool_id, int event_id, PyObject *obj) +{ + PyInterpreterState *is = _PyInterpreterState_Get(); + assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); + assert(0 <= event_id && event_id < PY_MONITORING_EVENTS); + PyObject *callback = is->monitoring_callables[tool_id][event_id]; + is->monitoring_callables[tool_id][event_id] = Py_XNewRef(obj); + return callback; +} + +static void +initialize_tools(PyCodeObject *code) +{ + uint8_t* tools = code->_co_monitoring->tools; + assert(tools != NULL); + int code_len = (int)Py_SIZE(code); + for (int i = 0; i < code_len; i++) { + _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; + int opcode = instr->op.code; + if (opcode == INSTRUMENTED_LINE) { + opcode = code->_co_monitoring->lines[i].original_opcode; + } + bool instrumented = is_instrumented(opcode); + if (instrumented) { + opcode = DE_INSTRUMENT[opcode]; + assert(opcode != 0); + } + opcode = _PyOpcode_Deopt[opcode]; + if (opcode_has_event(opcode)) { + if (instrumented) { + int8_t event; + if (opcode == RESUME) { + event = instr->op.arg != 0; + } + else { + event = EVENT_FOR_OPCODE[opcode]; + assert(event > 0); + } + assert(event >= 0); + assert(event < PY_MONITORING_INSTRUMENTED_EVENTS); + tools[i] = code->_co_monitoring->active_monitors.tools[event]; + CHECK(tools[i] != 0); + } + else { + tools[i] = 0; + } + } +#ifdef Py_DEBUG + /* Initialize tools for invalid locations to all ones to try to catch errors */ + else { + tools[i] = 0xff; + } + for (int j = 1; j <= _PyOpcode_Caches[opcode]; j++) { + tools[i+j] = 0xff; + } +#endif + i += _PyOpcode_Caches[opcode]; + } +} + +#define NO_LINE -128 + +static void +initialize_lines(PyCodeObject *code) +{ + _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines; + assert(line_data != NULL); + int code_len = (int)Py_SIZE(code); + PyCodeAddressRange range; + _PyCode_InitAddressRange(code, &range); + for (int i = 0; i < code->_co_firsttraceable && i < code_len; i++) { + line_data[i].original_opcode = 0; + line_data[i].line_delta = -127; + } + int current_line = -1; + for (int i = code->_co_firsttraceable; i < code_len; ) { + int opcode = _Py_GetBaseOpcode(code, i); + int line = _PyCode_CheckLineNumber(i*(int)sizeof(_Py_CODEUNIT), &range); + line_data[i].line_delta = compute_line_delta(code, i, line); + int length = instruction_length(code, i); + switch (opcode) { + case END_ASYNC_FOR: + case END_FOR: + case END_SEND: + case RESUME: + /* END_FOR cannot start a line, as it is skipped by FOR_ITER + * END_SEND cannot start a line, as it is skipped by SEND + * RESUME must not be instrumented with INSTRUMENT_LINE */ + line_data[i].original_opcode = 0; + break; + default: + if (line != current_line && line >= 0) { + line_data[i].original_opcode = opcode; + } + else { + line_data[i].original_opcode = 0; + } + if (line >= 0) { + current_line = line; + } + } + for (int j = 1; j < length; j++) { + line_data[i+j].original_opcode = 0; + line_data[i+j].line_delta = NO_LINE; + } + switch (opcode) { + case RETURN_VALUE: + case RAISE_VARARGS: + case RERAISE: + /* Blocks of code after these terminators + * should be treated as different lines */ + current_line = -1; + } + i += length; + } +} + +static void +initialize_line_tools(PyCodeObject *code, _Py_Monitors *all_events) +{ + uint8_t *line_tools = code->_co_monitoring->line_tools; + assert(line_tools != NULL); + int code_len = (int)Py_SIZE(code); + for (int i = 0; i < code_len; i++) { + line_tools[i] = all_events->tools[PY_MONITORING_EVENT_LINE]; + } +} + +static +int allocate_instrumentation_data(PyCodeObject *code) +{ + + if (code->_co_monitoring == NULL) { + code->_co_monitoring = PyMem_Malloc(sizeof(_PyCoMonitoringData)); + if (code->_co_monitoring == NULL) { + PyErr_NoMemory(); + return -1; + } + code->_co_monitoring->local_monitors = (_Py_Monitors){ 0 }; + code->_co_monitoring->active_monitors = (_Py_Monitors){ 0 }; + code->_co_monitoring->tools = NULL; + code->_co_monitoring->lines = NULL; + code->_co_monitoring->line_tools = NULL; + code->_co_monitoring->per_instruction_opcodes = NULL; + code->_co_monitoring->per_instruction_tools = NULL; + } + return 0; +} + +static int +update_instrumentation_data(PyCodeObject *code, PyInterpreterState *interp) +{ + int code_len = (int)Py_SIZE(code); + if (allocate_instrumentation_data(code)) { + return -1; + } + _Py_Monitors all_events = monitors_or( + interp->monitors, + code->_co_monitoring->local_monitors); + bool multitools = multiple_tools(&all_events); + if (code->_co_monitoring->tools == NULL && multitools) { + code->_co_monitoring->tools = PyMem_Malloc(code_len); + if (code->_co_monitoring->tools == NULL) { + PyErr_NoMemory(); + return -1; + } + initialize_tools(code); + } + if (all_events.tools[PY_MONITORING_EVENT_LINE]) { + if (code->_co_monitoring->lines == NULL) { + code->_co_monitoring->lines = PyMem_Malloc(code_len * sizeof(_PyCoLineInstrumentationData)); + if (code->_co_monitoring->lines == NULL) { + PyErr_NoMemory(); + return -1; + } + initialize_lines(code); + } + if (multitools && code->_co_monitoring->line_tools == NULL) { + code->_co_monitoring->line_tools = PyMem_Malloc(code_len); + if (code->_co_monitoring->line_tools == NULL) { + PyErr_NoMemory(); + return -1; + } + initialize_line_tools(code, &all_events); + } + } + if (all_events.tools[PY_MONITORING_EVENT_INSTRUCTION]) { + if (code->_co_monitoring->per_instruction_opcodes == NULL) { + code->_co_monitoring->per_instruction_opcodes = PyMem_Malloc(code_len * sizeof(_PyCoLineInstrumentationData)); + if (code->_co_monitoring->per_instruction_opcodes == NULL) { + PyErr_NoMemory(); + return -1; + } + /* This may not be necessary, as we can initialize this memory lazily, but it helps catch errors. */ + for (int i = 0; i < code_len; i++) { + code->_co_monitoring->per_instruction_opcodes[i] = 0; + } + } + if (multitools && code->_co_monitoring->per_instruction_tools == NULL) { + code->_co_monitoring->per_instruction_tools = PyMem_Malloc(code_len); + if (code->_co_monitoring->per_instruction_tools == NULL) { + PyErr_NoMemory(); + return -1; + } + /* This may not be necessary, as we can initialize this memory lazily, but it helps catch errors. */ + for (int i = 0; i < code_len; i++) { + code->_co_monitoring->per_instruction_tools[i] = 0; + } + } + } + return 0; +} + +static const uint8_t super_instructions[256] = { + [LOAD_FAST__LOAD_FAST] = 1, + [LOAD_FAST__LOAD_CONST] = 1, + [STORE_FAST__LOAD_FAST] = 1, + [STORE_FAST__STORE_FAST] = 1, + [LOAD_CONST__LOAD_FAST] = 1, +}; + +/* Should use instruction metadata for this */ +static bool +is_super_instruction(int opcode) { + return super_instructions[opcode] != 0; +} + +int +_Py_Instrument(PyCodeObject *code, PyInterpreterState *interp) +{ + + if (is_version_up_to_date(code, interp)) { + assert( + interp->monitoring_version == 0 || + instrumentation_cross_checks(interp, code) + ); + return 0; + } + int code_len = (int)Py_SIZE(code); + if (update_instrumentation_data(code, interp)) { + return -1; + } + _Py_Monitors active_events = monitors_or( + interp->monitors, + code->_co_monitoring->local_monitors); + _Py_Monitors new_events; + _Py_Monitors removed_events; + + bool restarted = interp->last_restart_version > code->_co_instrumentation_version; + if (restarted) { + removed_events = code->_co_monitoring->active_monitors; + new_events = active_events; + } + else { + removed_events = monitors_sub(code->_co_monitoring->active_monitors, active_events); + new_events = monitors_sub(active_events, code->_co_monitoring->active_monitors); + assert(monitors_are_empty(monitors_and(new_events, removed_events))); + } + code->_co_monitoring->active_monitors = active_events; + code->_co_instrumentation_version = interp->monitoring_version; + if (monitors_are_empty(new_events) && monitors_are_empty(removed_events)) { +#ifdef INSTRUMENT_DEBUG + sanity_check_instrumentation(code); +#endif + return 0; + } + /* Insert instrumentation */ + for (int i = 0; i < code_len; i+= instruction_length(code, i)) { + _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; + if (is_super_instruction(instr->op.code)) { + instr->op.code = _PyOpcode_Deopt[instr->op.code]; + } + CHECK(instr->op.code != 0); + int base_opcode = _Py_GetBaseOpcode(code, i); + if (opcode_has_event(base_opcode)) { + int8_t event; + if (base_opcode == RESUME) { + event = instr->op.arg > 0; + } + else { + event = EVENT_FOR_OPCODE[base_opcode]; + assert(event > 0); + } + uint8_t removed_tools = removed_events.tools[event]; + if (removed_tools) { + remove_tools(code, i, event, removed_tools); + } + uint8_t new_tools = new_events.tools[event]; + if (new_tools) { + add_tools(code, i, event, new_tools); + } + } + } + uint8_t new_line_tools = new_events.tools[PY_MONITORING_EVENT_LINE]; + uint8_t removed_line_tools = removed_events.tools[PY_MONITORING_EVENT_LINE]; + if (new_line_tools | removed_line_tools) { + _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines; + for (int i = code->_co_firsttraceable; i < code_len;) { + if (line_data[i].original_opcode) { + if (removed_line_tools) { + remove_line_tools(code, i, removed_line_tools); + } + if (new_line_tools) { + add_line_tools(code, i, new_line_tools); + } + } + i += instruction_length(code, i); + } + } + uint8_t new_per_instruction_tools = new_events.tools[PY_MONITORING_EVENT_INSTRUCTION]; + uint8_t removed_per_instruction_tools = removed_events.tools[PY_MONITORING_EVENT_INSTRUCTION]; + if (new_per_instruction_tools | removed_per_instruction_tools) { + for (int i = code->_co_firsttraceable; i < code_len;) { + int opcode = _Py_GetBaseOpcode(code, i); + if (opcode == RESUME || opcode == END_FOR) { + i += instruction_length(code, i); + continue; + } + if (removed_per_instruction_tools) { + remove_per_instruction_tools(code, i, removed_per_instruction_tools); + } + if (new_per_instruction_tools) { + add_per_instruction_tools(code, i, new_per_instruction_tools); + } + i += instruction_length(code, i); + } + } +#ifdef INSTRUMENT_DEBUG + sanity_check_instrumentation(code); +#endif + return 0; +} + +#define C_RETURN_EVENTS \ + ((1 << PY_MONITORING_EVENT_C_RETURN) | \ + (1 << PY_MONITORING_EVENT_C_RAISE)) + +#define C_CALL_EVENTS \ + (C_RETURN_EVENTS | (1 << PY_MONITORING_EVENT_CALL)) + + +static int +instrument_all_executing_code_objects(PyInterpreterState *interp) { + _PyRuntimeState *runtime = &_PyRuntime; + HEAD_LOCK(runtime); + PyThreadState* ts = PyInterpreterState_ThreadHead(interp); + HEAD_UNLOCK(runtime); + while (ts) { + _PyInterpreterFrame *frame = ts->cframe->current_frame; + while (frame) { + if (frame->owner != FRAME_OWNED_BY_CSTACK) { + if (_Py_Instrument(frame->f_code, interp)) { + return -1; + } + } + frame = frame->previous; + } + HEAD_LOCK(runtime); + ts = PyThreadState_Next(ts); + HEAD_UNLOCK(runtime); + } + return 0; +} + +static void +set_events(_Py_Monitors *m, int tool_id, _PyMonitoringEventSet events) +{ + assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); + for (int e = 0; e < PY_MONITORING_UNGROUPED_EVENTS; e++) { + uint8_t *tools = &m->tools[e]; + int val = (events >> e) & 1; + *tools &= ~(1 << tool_id); + *tools |= (val << tool_id); + } +} + +static int +check_tool(PyInterpreterState *interp, int tool_id) +{ + if (tool_id < PY_MONITORING_SYS_PROFILE_ID && + interp->monitoring_tool_names[tool_id] == NULL + ) { + PyErr_Format(PyExc_ValueError, "tool %d is not in use", tool_id); + return -1; + } + return 0; +} + +int +_PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events) +{ + assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); + PyInterpreterState *interp = _PyInterpreterState_Get(); + assert(events < (1 << PY_MONITORING_UNGROUPED_EVENTS)); + if (check_tool(interp, tool_id)) { + return -1; + } + uint32_t existing_events = get_events(&interp->monitors, tool_id); + if (existing_events == events) { + return 0; + } + set_events(&interp->monitors, tool_id, events); + interp->monitoring_version++; + return instrument_all_executing_code_objects(interp); +} + +int +_PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEventSet events) +{ + assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); + PyInterpreterState *interp = _PyInterpreterState_Get(); + assert(events < (1 << PY_MONITORING_UNGROUPED_EVENTS)); + if (check_tool(interp, tool_id)) { + return -1; + } + if (allocate_instrumentation_data(code)) { + return -1; + } + _Py_Monitors *local = &code->_co_monitoring->local_monitors; + uint32_t existing_events = get_events(local, tool_id); + if (existing_events == events) { + return 0; + } + set_events(local, tool_id, events); + if (is_version_up_to_date(code, interp)) { + /* Force instrumentation update */ + code->_co_instrumentation_version = UINT64_MAX; + } + if (_Py_Instrument(code, interp)) { + return -1; + } + return 0; +} + +/*[clinic input] +module monitoring +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=37257f5987a360cf]*/ +/*[clinic end generated code]*/ + +#include "clinic/instrumentation.c.h" + +static int +check_valid_tool(int tool_id) +{ + if (tool_id < 0 || tool_id >= PY_MONITORING_SYS_PROFILE_ID) { + PyErr_Format(PyExc_ValueError, "invalid tool %d (must be between 0 and 5)", tool_id); + return -1; + } + return 0; +} + +/*[clinic input] +monitoring.use_tool_id + + tool_id: int + name: object + / + +[clinic start generated code]*/ + +static PyObject * +monitoring_use_tool_id_impl(PyObject *module, int tool_id, PyObject *name) +/*[clinic end generated code: output=30d76dc92b7cd653 input=ebc453761c621be1]*/ +{ + if (check_valid_tool(tool_id)) { + return NULL; + } + if (!PyUnicode_Check(name)) { + PyErr_SetString(PyExc_ValueError, "tool name must be a str"); + return NULL; + } + PyInterpreterState *interp = _PyInterpreterState_Get(); + if (interp->monitoring_tool_names[tool_id] != NULL) { + PyErr_Format(PyExc_ValueError, "tool %d is already in use", tool_id); + return NULL; + } + interp->monitoring_tool_names[tool_id] = Py_NewRef(name); + Py_RETURN_NONE; +} + +/*[clinic input] +monitoring.free_tool_id + + tool_id: int + / + +[clinic start generated code]*/ + +static PyObject * +monitoring_free_tool_id_impl(PyObject *module, int tool_id) +/*[clinic end generated code: output=86c2d2a1219a8591 input=a23fb6be3a8618e9]*/ +{ + if (check_valid_tool(tool_id)) { + return NULL; + } + PyInterpreterState *interp = _PyInterpreterState_Get(); + Py_CLEAR(interp->monitoring_tool_names[tool_id]); + Py_RETURN_NONE; +} + +/*[clinic input] +monitoring.get_tool + + tool_id: int + / + +[clinic start generated code]*/ + +static PyObject * +monitoring_get_tool_impl(PyObject *module, int tool_id) +/*[clinic end generated code: output=1c05a98b404a9a16 input=eeee9bebd0bcae9d]*/ + +/*[clinic end generated code]*/ +{ + if (check_valid_tool(tool_id)) { + return NULL; + } + PyInterpreterState *interp = _PyInterpreterState_Get(); + PyObject *name = interp->monitoring_tool_names[tool_id]; + if (name == NULL) { + Py_RETURN_NONE; + } + return Py_NewRef(name); +} + +/*[clinic input] +monitoring.register_callback + + + tool_id: int + event: int + func: object + / + +[clinic start generated code]*/ + +static PyObject * +monitoring_register_callback_impl(PyObject *module, int tool_id, int event, + PyObject *func) +/*[clinic end generated code: output=e64daa363004030c input=df6d70ea4cf81007]*/ +{ + if (check_valid_tool(tool_id)) { + return NULL; + } + if (_Py_popcount32(event) != 1) { + PyErr_SetString(PyExc_ValueError, "The callback can only be set for one event at a time"); + return NULL; + } + int event_id = _Py_bit_length(event)-1; + if (event_id < 0 || event_id >= PY_MONITORING_EVENTS) { + PyErr_Format(PyExc_ValueError, "invalid event %d", event); + return NULL; + } + if (func == Py_None) { + func = NULL; + } + func = _PyMonitoring_RegisterCallback(tool_id, event_id, func); + if (func == NULL) { + Py_RETURN_NONE; + } + return func; +} + +/*[clinic input] +monitoring.get_events -> int + + tool_id: int + / + +[clinic start generated code]*/ + +static int +monitoring_get_events_impl(PyObject *module, int tool_id) +/*[clinic end generated code: output=4450cc13f826c8c0 input=a64b238f76c4b2f7]*/ +{ + if (check_valid_tool(tool_id)) { + return -1; + } + _Py_Monitors *m = &_PyInterpreterState_Get()->monitors; + _PyMonitoringEventSet event_set = get_events(m, tool_id); + return event_set; +} + +/*[clinic input] +monitoring.set_events + + tool_id: int + event_set: int + / + +[clinic start generated code]*/ + +static PyObject * +monitoring_set_events_impl(PyObject *module, int tool_id, int event_set) +/*[clinic end generated code: output=1916c1e49cfb5bdb input=a77ba729a242142b]*/ +{ + if (check_valid_tool(tool_id)) { + return NULL; + } + if (event_set < 0 || event_set >= (1 << PY_MONITORING_EVENTS)) { + PyErr_Format(PyExc_ValueError, "invalid event set 0x%x", event_set); + return NULL; + } + if ((event_set & C_RETURN_EVENTS) && (event_set & C_CALL_EVENTS) != C_CALL_EVENTS) { + PyErr_Format(PyExc_ValueError, "cannot set C_RETURN or C_RAISE events independently"); + return NULL; + } + event_set &= ~C_RETURN_EVENTS; + if (_PyMonitoring_SetEvents(tool_id, event_set)) { + return NULL; + } + Py_RETURN_NONE; +} + +/*[clinic input] +monitoring.get_local_events -> int + + tool_id: int + code: object + / + +[clinic start generated code]*/ + +static int +monitoring_get_local_events_impl(PyObject *module, int tool_id, + PyObject *code) +/*[clinic end generated code: output=d3e92c1c9c1de8f9 input=bb0f927530386a94]*/ +{ + if (!PyCode_Check(code)) { + PyErr_Format( + PyExc_TypeError, + "code must be a code object" + ); + return -1; + } + if (check_valid_tool(tool_id)) { + return -1; + } + _PyMonitoringEventSet event_set = 0; + _PyCoMonitoringData *data = ((PyCodeObject *)code)->_co_monitoring; + if (data != NULL) { + for (int e = 0; e < PY_MONITORING_UNGROUPED_EVENTS; e++) { + if ((data->local_monitors.tools[e] >> tool_id) & 1) { + event_set |= (1 << e); + } + } + } + return event_set; +} + +/*[clinic input] +monitoring.set_local_events + + tool_id: int + code: object + event_set: int + / + +[clinic start generated code]*/ + +static PyObject * +monitoring_set_local_events_impl(PyObject *module, int tool_id, + PyObject *code, int event_set) +/*[clinic end generated code: output=68cc755a65dfea99 input=5655ecd78d937a29]*/ +{ + if (!PyCode_Check(code)) { + PyErr_Format( + PyExc_TypeError, + "code must be a code object" + ); + return NULL; + } + if (check_valid_tool(tool_id)) { + return NULL; + } + if (event_set < 0 || event_set >= (1 << PY_MONITORING_EVENTS)) { + PyErr_Format(PyExc_ValueError, "invalid event set 0x%x", event_set); + return NULL; + } + if ((event_set & C_RETURN_EVENTS) && (event_set & C_CALL_EVENTS) != C_CALL_EVENTS) { + PyErr_Format(PyExc_ValueError, "cannot set C_RETURN or C_RAISE events independently"); + return NULL; + } + event_set &= ~C_RETURN_EVENTS; + if (_PyMonitoring_SetLocalEvents((PyCodeObject*)code, tool_id, event_set)) { + return NULL; + } + Py_RETURN_NONE; +} + +/*[clinic input] +monitoring.restart_events + +[clinic start generated code]*/ + +static PyObject * +monitoring_restart_events_impl(PyObject *module) +/*[clinic end generated code: output=e025dd5ba33314c4 input=add8a855063c8008]*/ +{ + /* We want to ensure that: + * last restart version > instrumented version for all code objects + * last restart version < current version + */ + PyInterpreterState *interp = _PyInterpreterState_Get(); + interp->last_restart_version = interp->monitoring_version + 1; + interp->monitoring_version = interp->last_restart_version + 1; + if (instrument_all_executing_code_objects(interp)) { + return NULL; + } + Py_RETURN_NONE; +} + +static int +add_power2_constant(PyObject *obj, const char *name, int i) +{ + PyObject *val = PyLong_FromLong(1<monitors.tools[e]; + if (tools == 0) { + continue; + } + PyObject *tools_obj = PyLong_FromLong(tools); + assert(tools_obj != NULL); + int err = PyDict_SetItemString(res, event_names[e], tools_obj); + Py_DECREF(tools_obj); + if (err < 0) { + Py_DECREF(res); + return NULL; + } + } + return res; +} + +static PyMethodDef methods[] = { + MONITORING_USE_TOOL_ID_METHODDEF + MONITORING_FREE_TOOL_ID_METHODDEF + MONITORING_GET_TOOL_METHODDEF + MONITORING_REGISTER_CALLBACK_METHODDEF + MONITORING_GET_EVENTS_METHODDEF + MONITORING_SET_EVENTS_METHODDEF + MONITORING_GET_LOCAL_EVENTS_METHODDEF + MONITORING_SET_LOCAL_EVENTS_METHODDEF + MONITORING_RESTART_EVENTS_METHODDEF + MONITORING__ALL_EVENTS_METHODDEF + {NULL, NULL} // sentinel +}; + +static struct PyModuleDef monitoring_module = { + PyModuleDef_HEAD_INIT, + .m_name = "sys.monitoring", + .m_size = -1, /* multiple "initialization" just copies the module dict. */ + .m_methods = methods, +}; + +PyObject *_Py_CreateMonitoringObject(void) +{ + PyObject *mod = _PyModule_CreateInitialized(&monitoring_module, PYTHON_API_VERSION); + if (mod == NULL) { + return NULL; + } + if (PyObject_SetAttrString(mod, "DISABLE", &DISABLE)) { + goto error; + } + if (PyObject_SetAttrString(mod, "MISSING", &_PyInstrumentation_MISSING)) { + goto error; + } + PyObject *events = _PyNamespace_New(NULL); + if (events == NULL) { + goto error; + } + int err = PyObject_SetAttrString(mod, "events", events); + Py_DECREF(events); + if (err) { + goto error; + } + for (int i = 0; i < PY_MONITORING_EVENTS; i++) { + if (add_power2_constant(events, event_names[i], i)) { + goto error; + } + } + err = PyObject_SetAttrString(events, "NO_EVENTS", _PyLong_GetZero()); + if (err) goto error; + PyObject *val = PyLong_FromLong(PY_MONITORING_DEBUGGER_ID); + err = PyObject_SetAttrString(mod, "DEBUGGER_ID", val); + Py_DECREF(val); + if (err) goto error; + val = PyLong_FromLong(PY_MONITORING_COVERAGE_ID); + err = PyObject_SetAttrString(mod, "COVERAGE_ID", val); + Py_DECREF(val); + if (err) goto error; + val = PyLong_FromLong(PY_MONITORING_PROFILER_ID); + err = PyObject_SetAttrString(mod, "PROFILER_ID", val); + Py_DECREF(val); + if (err) goto error; + val = PyLong_FromLong(PY_MONITORING_OPTIMIZER_ID); + err = PyObject_SetAttrString(mod, "OPTIMIZER_ID", val); + Py_DECREF(val); + if (err) goto error; + return mod; +error: + Py_DECREF(mod); + return NULL; +} diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c new file mode 100644 index 000000000000..cf345bddda79 --- /dev/null +++ b/Python/legacy_tracing.c @@ -0,0 +1,528 @@ +/* Support for legacy tracing on top of PEP 669 instrumentation + * Provides callables to forward PEP 669 events to legacy events. + */ + +#include +#include "Python.h" +#include "pycore_ceval.h" +#include "pycore_object.h" +#include "pycore_sysmodule.h" + +typedef struct _PyLegacyEventHandler { + PyObject_HEAD + vectorcallfunc vectorcall; + int event; +} _PyLegacyEventHandler; + +/* The Py_tracefunc function expects the following arguments: + * obj: the trace object (PyObject *) + * frame: the current frame (PyFrameObject *) + * kind: the kind of event, see PyTrace_XXX #defines (int) + * arg: The arg (a PyObject *) + */ + +static PyObject * +call_profile_func(_PyLegacyEventHandler *self, PyObject *arg) +{ + PyThreadState *tstate = _PyThreadState_GET(); + if (tstate->c_profilefunc == NULL) { + Py_RETURN_NONE; + } + PyFrameObject *frame = PyEval_GetFrame(); + if (frame == NULL) { + PyErr_SetString(PyExc_SystemError, + "Missing frame when calling profile function."); + return NULL; + } + Py_INCREF(frame); + int err = tstate->c_profilefunc(tstate->c_profileobj, frame, self->event, arg); + Py_DECREF(frame); + if (err) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +sys_profile_func2( + _PyLegacyEventHandler *self, PyObject *const *args, + size_t nargsf, PyObject *kwnames +) { + assert(kwnames == NULL); + assert(PyVectorcall_NARGS(nargsf) == 2); + return call_profile_func(self, Py_None); +} + +static PyObject * +sys_profile_func3( + _PyLegacyEventHandler *self, PyObject *const *args, + size_t nargsf, PyObject *kwnames +) { + assert(kwnames == NULL); + assert(PyVectorcall_NARGS(nargsf) == 3); + return call_profile_func(self, args[2]); +} + +static PyObject * +sys_profile_call_or_return( + _PyLegacyEventHandler *self, PyObject *const *args, + size_t nargsf, PyObject *kwnames +) { + assert(kwnames == NULL); + assert(PyVectorcall_NARGS(nargsf) == 4); + PyObject *callable = args[2]; + if (PyCFunction_Check(callable)) { + return call_profile_func(self, callable); + } + if (Py_TYPE(callable) == &PyMethodDescr_Type) { + PyObject *self_arg = args[3]; + /* For backwards compatibility need to + * convert to builtin method */ + + /* If no arg, skip */ + if (self_arg == &_PyInstrumentation_MISSING) { + Py_RETURN_NONE; + } + PyObject *meth = Py_TYPE(callable)->tp_descr_get( + callable, self_arg, (PyObject*)Py_TYPE(self_arg)); + if (meth == NULL) { + return NULL; + } + PyObject *res = call_profile_func(self, meth); + Py_DECREF(meth); + return res; + } + Py_RETURN_NONE; +} + +static PyObject * +call_trace_func(_PyLegacyEventHandler *self, PyObject *arg) +{ + PyThreadState *tstate = _PyThreadState_GET(); + if (tstate->c_tracefunc == NULL) { + Py_RETURN_NONE; + } + PyFrameObject *frame = PyEval_GetFrame(); + if (frame == NULL) { + PyErr_SetString(PyExc_SystemError, + "Missing frame when calling trace function."); + return NULL; + } + Py_INCREF(frame); + int err = tstate->c_tracefunc(tstate->c_traceobj, frame, self->event, arg); + Py_DECREF(frame); + if (err) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +sys_trace_exception_func( + _PyLegacyEventHandler *self, PyObject *const *args, + size_t nargsf, PyObject *kwnames +) { + assert(kwnames == NULL); + assert(PyVectorcall_NARGS(nargsf) == 3); + PyObject *exc = args[2]; + assert(PyExceptionInstance_Check(exc)); + PyObject *type = (PyObject *)Py_TYPE(exc); + PyObject *tb = PyException_GetTraceback(exc); + if (tb == NULL) { + tb = Py_NewRef(Py_None); + } + PyObject *tuple = PyTuple_Pack(3, type, exc, tb); + Py_DECREF(tb); + if (tuple == NULL) { + return NULL; + } + PyObject *res = call_trace_func(self, tuple); + Py_DECREF(tuple); + return res; +} + +static PyObject * +sys_trace_func2( + _PyLegacyEventHandler *self, PyObject *const *args, + size_t nargsf, PyObject *kwnames +) { + assert(kwnames == NULL); + assert(PyVectorcall_NARGS(nargsf) == 2); + return call_trace_func(self, Py_None); +} + +static PyObject * +sys_trace_return( + _PyLegacyEventHandler *self, PyObject *const *args, + size_t nargsf, PyObject *kwnames +) { + assert(!PyErr_Occurred()); + assert(kwnames == NULL); + assert(PyVectorcall_NARGS(nargsf) == 3); + assert(PyCode_Check(args[0])); + PyObject *val = args[2]; + PyObject *res = call_trace_func(self, val); + return res; +} + +static PyObject * +sys_trace_yield( + _PyLegacyEventHandler *self, PyObject *const *args, + size_t nargsf, PyObject *kwnames +) { + assert(kwnames == NULL); + assert(PyVectorcall_NARGS(nargsf) == 3); + return call_trace_func(self, args[2]); +} + +static PyObject * +sys_trace_instruction_func( + _PyLegacyEventHandler *self, PyObject *const *args, + size_t nargsf, PyObject *kwnames +) { + assert(kwnames == NULL); + assert(PyVectorcall_NARGS(nargsf) == 2); + PyFrameObject *frame = PyEval_GetFrame(); + if (frame == NULL) { + PyErr_SetString(PyExc_SystemError, + "Missing frame when calling trace function."); + return NULL; + } + if (!frame->f_trace_opcodes) { + Py_RETURN_NONE; + } + Py_INCREF(frame); + PyThreadState *tstate = _PyThreadState_GET(); + int err = tstate->c_tracefunc(tstate->c_traceobj, frame, self->event, Py_None); + frame->f_lineno = 0; + Py_DECREF(frame); + if (err) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +trace_line( + PyThreadState *tstate, _PyLegacyEventHandler *self, + PyFrameObject *frame, int line +) { + if (!frame->f_trace_lines) { + Py_RETURN_NONE; + } + if (line < 0) { + Py_RETURN_NONE; + } + frame ->f_last_traced_line = line; + Py_INCREF(frame); + frame->f_lineno = line; + int err = tstate->c_tracefunc(tstate->c_traceobj, frame, self->event, Py_None); + frame->f_lineno = 0; + Py_DECREF(frame); + if (err) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +sys_trace_line_func( + _PyLegacyEventHandler *self, PyObject *const *args, + size_t nargsf, PyObject *kwnames +) { + assert(kwnames == NULL); + PyThreadState *tstate = _PyThreadState_GET(); + if (tstate->c_tracefunc == NULL) { + Py_RETURN_NONE; + } + assert(PyVectorcall_NARGS(nargsf) == 2); + int line = _PyLong_AsInt(args[1]); + assert(line >= 0); + PyFrameObject *frame = PyEval_GetFrame(); + if (frame == NULL) { + PyErr_SetString(PyExc_SystemError, + "Missing frame when calling trace function."); + return NULL; + } + assert(args[0] == (PyObject *)frame->f_frame->f_code); + if (frame ->f_last_traced_line == line) { + /* Already traced this line */ + Py_RETURN_NONE; + } + return trace_line(tstate, self, frame, line); +} + + +static PyObject * +sys_trace_jump_func( + _PyLegacyEventHandler *self, PyObject *const *args, + size_t nargsf, PyObject *kwnames +) { + assert(kwnames == NULL); + PyThreadState *tstate = _PyThreadState_GET(); + if (tstate->c_tracefunc == NULL) { + Py_RETURN_NONE; + } + assert(PyVectorcall_NARGS(nargsf) == 3); + int from = _PyLong_AsInt(args[1])/sizeof(_Py_CODEUNIT); + assert(from >= 0); + int to = _PyLong_AsInt(args[2])/sizeof(_Py_CODEUNIT); + assert(to >= 0); + PyFrameObject *frame = PyEval_GetFrame(); + if (frame == NULL) { + PyErr_SetString(PyExc_SystemError, + "Missing frame when calling trace function."); + return NULL; + } + if (!frame->f_trace_lines) { + Py_RETURN_NONE; + } + PyCodeObject *code = (PyCodeObject *)args[0]; + assert(PyCode_Check(code)); + assert(code == frame->f_frame->f_code); + /* We can call _Py_Instrumentation_GetLine because we always set + * line events for tracing */ + int to_line = _Py_Instrumentation_GetLine(code, to); + /* Backward jump: Always generate event + * Forward jump: Only generate event if jumping to different line. */ + if (to > from && frame->f_last_traced_line == to_line) { + /* Already traced this line */ + Py_RETURN_NONE; + } + return trace_line(tstate, self, frame, to_line); +} + +/* We don't care about the exception here, + * we just treat it as a possible new line + */ +static PyObject * +sys_trace_exception_handled( + _PyLegacyEventHandler *self, PyObject *const *args, + size_t nargsf, PyObject *kwnames +) { + assert(kwnames == NULL); + PyThreadState *tstate = _PyThreadState_GET(); + if (tstate->c_tracefunc == NULL) { + Py_RETURN_NONE; + } + assert(PyVectorcall_NARGS(nargsf) == 3); + PyFrameObject *frame = PyEval_GetFrame(); + PyCodeObject *code = (PyCodeObject *)args[0]; + assert(PyCode_Check(code)); + assert(code == frame->f_frame->f_code); + assert(PyLong_Check(args[1])); + int offset = _PyLong_AsInt(args[1])/sizeof(_Py_CODEUNIT); + /* We can call _Py_Instrumentation_GetLine because we always set + * line events for tracing */ + int line = _Py_Instrumentation_GetLine(code, offset); + if (frame->f_last_traced_line == line) { + /* Already traced this line */ + Py_RETURN_NONE; + } + return trace_line(tstate, self, frame, line); +} + + +PyTypeObject _PyLegacyEventHandler_Type = { + _PyVarObject_IMMORTAL_INIT(&PyType_Type, 0), + "sys.legacy_event_handler", + sizeof(_PyLegacyEventHandler), + .tp_dealloc = (destructor)PyObject_Free, + .tp_vectorcall_offset = offsetof(_PyLegacyEventHandler, vectorcall), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_VECTORCALL | Py_TPFLAGS_DISALLOW_INSTANTIATION, + .tp_call = PyVectorcall_Call, +}; + +static int +set_callbacks(int tool, vectorcallfunc vectorcall, int legacy_event, int event1, int event2) +{ + _PyLegacyEventHandler *callback = + PyObject_NEW(_PyLegacyEventHandler, &_PyLegacyEventHandler_Type); + if (callback == NULL) { + return -1; + } + callback->vectorcall = vectorcall; + callback->event = legacy_event; + Py_XDECREF(_PyMonitoring_RegisterCallback(tool, event1, (PyObject *)callback)); + if (event2 >= 0) { + Py_XDECREF(_PyMonitoring_RegisterCallback(tool, event2, (PyObject *)callback)); + } + Py_DECREF(callback); + return 0; +} + +#ifndef NDEBUG +/* Ensure that tstate is valid: sanity check for PyEval_AcquireThread() and + PyEval_RestoreThread(). Detect if tstate memory was freed. It can happen + when a thread continues to run after Python finalization, especially + daemon threads. */ +static int +is_tstate_valid(PyThreadState *tstate) +{ + assert(!_PyMem_IsPtrFreed(tstate)); + assert(!_PyMem_IsPtrFreed(tstate->interp)); + return 1; +} +#endif + +int +_PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) +{ + assert(is_tstate_valid(tstate)); + /* The caller must hold the GIL */ + assert(PyGILState_Check()); + + /* Call _PySys_Audit() in the context of the current thread state, + even if tstate is not the current thread state. */ + PyThreadState *current_tstate = _PyThreadState_GET(); + if (_PySys_Audit(current_tstate, "sys.setprofile", NULL) < 0) { + return -1; + } + /* Setup PEP 669 monitoring callbacks and events. */ + if (!tstate->interp->sys_profile_initialized) { + tstate->interp->sys_profile_initialized = true; + if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID, + (vectorcallfunc)sys_profile_func2, PyTrace_CALL, + PY_MONITORING_EVENT_PY_START, PY_MONITORING_EVENT_PY_RESUME)) { + return -1; + } + if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID, + (vectorcallfunc)sys_profile_func3, PyTrace_RETURN, + PY_MONITORING_EVENT_PY_RETURN, PY_MONITORING_EVENT_PY_YIELD)) { + return -1; + } + if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID, + (vectorcallfunc)sys_profile_func2, PyTrace_RETURN, + PY_MONITORING_EVENT_PY_UNWIND, -1)) { + return -1; + } + if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID, + (vectorcallfunc)sys_profile_call_or_return, PyTrace_C_CALL, + PY_MONITORING_EVENT_CALL, -1)) { + return -1; + } + if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID, + (vectorcallfunc)sys_profile_call_or_return, PyTrace_C_RETURN, + PY_MONITORING_EVENT_C_RETURN, -1)) { + return -1; + } + if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID, + (vectorcallfunc)sys_profile_call_or_return, PyTrace_C_EXCEPTION, + PY_MONITORING_EVENT_C_RAISE, -1)) { + return -1; + } + } + + int delta = (func != NULL) - (tstate->c_profilefunc != NULL); + tstate->c_profilefunc = func; + PyObject *old_profileobj = tstate->c_profileobj; + tstate->c_profileobj = Py_XNewRef(arg); + Py_XDECREF(old_profileobj); + tstate->interp->sys_profiling_threads += delta; + assert(tstate->interp->sys_profiling_threads >= 0); + + uint32_t events = 0; + if (tstate->interp->sys_profiling_threads) { + events = + (1 << PY_MONITORING_EVENT_PY_START) | (1 << PY_MONITORING_EVENT_PY_RESUME) | + (1 << PY_MONITORING_EVENT_PY_RETURN) | (1 << PY_MONITORING_EVENT_PY_YIELD) | + (1 << PY_MONITORING_EVENT_CALL) | (1 << PY_MONITORING_EVENT_PY_UNWIND); + } + return _PyMonitoring_SetEvents(PY_MONITORING_SYS_PROFILE_ID, events); +} + +int +_PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) +{ + assert(is_tstate_valid(tstate)); + /* The caller must hold the GIL */ + assert(PyGILState_Check()); + + /* Call _PySys_Audit() in the context of the current thread state, + even if tstate is not the current thread state. */ + PyThreadState *current_tstate = _PyThreadState_GET(); + if (_PySys_Audit(current_tstate, "sys.settrace", NULL) < 0) { + return -1; + } + + assert(tstate->interp->sys_tracing_threads >= 0); + /* Setup PEP 669 monitoring callbacks and events. */ + if (!tstate->interp->sys_trace_initialized) { + tstate->interp->sys_trace_initialized = true; + if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, + (vectorcallfunc)sys_trace_func2, PyTrace_CALL, + PY_MONITORING_EVENT_PY_START, PY_MONITORING_EVENT_PY_RESUME)) { + return -1; + } + if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, + (vectorcallfunc)sys_trace_func2, PyTrace_CALL, + PY_MONITORING_EVENT_PY_THROW, -1)) { + return -1; + } + if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, + (vectorcallfunc)sys_trace_return, PyTrace_RETURN, + PY_MONITORING_EVENT_PY_RETURN, -1)) { + return -1; + } + if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, + (vectorcallfunc)sys_trace_yield, PyTrace_RETURN, + PY_MONITORING_EVENT_PY_YIELD, -1)) { + return -1; + } + if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, + (vectorcallfunc)sys_trace_exception_func, PyTrace_EXCEPTION, + PY_MONITORING_EVENT_RAISE, PY_MONITORING_EVENT_STOP_ITERATION)) { + return -1; + } + if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, + (vectorcallfunc)sys_trace_line_func, PyTrace_LINE, + PY_MONITORING_EVENT_LINE, -1)) { + return -1; + } + if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, + (vectorcallfunc)sys_trace_func2, PyTrace_RETURN, + PY_MONITORING_EVENT_PY_UNWIND, -1)) { + return -1; + } + if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, + (vectorcallfunc)sys_trace_jump_func, PyTrace_LINE, + PY_MONITORING_EVENT_JUMP, PY_MONITORING_EVENT_BRANCH)) { + return -1; + } + if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, + (vectorcallfunc)sys_trace_instruction_func, PyTrace_OPCODE, + PY_MONITORING_EVENT_INSTRUCTION, -1)) { + return -1; + } + if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, + (vectorcallfunc)sys_trace_exception_handled, PyTrace_LINE, + PY_MONITORING_EVENT_EXCEPTION_HANDLED, -1)) { + return -1; + } + } + + int delta = (func != NULL) - (tstate->c_tracefunc != NULL); + tstate->c_tracefunc = func; + PyObject *old_traceobj = tstate->c_traceobj; + tstate->c_traceobj = Py_XNewRef(arg); + Py_XDECREF(old_traceobj); + tstate->interp->sys_tracing_threads += delta; + assert(tstate->interp->sys_tracing_threads >= 0); + + uint32_t events = 0; + if (tstate->interp->sys_tracing_threads) { + events = + (1 << PY_MONITORING_EVENT_PY_START) | (1 << PY_MONITORING_EVENT_PY_RESUME) | + (1 << PY_MONITORING_EVENT_PY_RETURN) | (1 << PY_MONITORING_EVENT_PY_YIELD) | + (1 << PY_MONITORING_EVENT_RAISE) | (1 << PY_MONITORING_EVENT_LINE) | + (1 << PY_MONITORING_EVENT_JUMP) | (1 << PY_MONITORING_EVENT_BRANCH) | + (1 << PY_MONITORING_EVENT_PY_UNWIND) | (1 << PY_MONITORING_EVENT_PY_THROW) | + (1 << PY_MONITORING_EVENT_STOP_ITERATION) | + (1 << PY_MONITORING_EVENT_EXCEPTION_HANDLED); + if (tstate->interp->f_opcode_trace_set) { + events |= (1 << PY_MONITORING_EVENT_INSTRUCTION); + } + } + return _PyMonitoring_SetEvents(PY_MONITORING_SYS_TRACE_ID, events); +} diff --git a/Python/makeopcodetargets.py b/Python/makeopcodetargets.py index 33a4b4a76a12..5aa31803397c 100755 --- a/Python/makeopcodetargets.py +++ b/Python/makeopcodetargets.py @@ -32,7 +32,6 @@ def write_contents(f): """ opcode = find_module('opcode') targets = ['_unknown_opcode'] * 256 - targets[255] = "TARGET_DO_TRACING" for opname, op in opcode.opmap.items(): if not opcode.is_pseudo(op): targets[op] = "TARGET_%s" % opname diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index f57b76aeb310..4681ed03aff5 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -13,6 +13,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 0; case RESUME: return 0; + case INSTRUMENTED_RESUME: + return 0; case LOAD_CLOSURE: return 0; case LOAD_FAST_CHECK: @@ -39,6 +41,12 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 0; case END_FOR: return 1+1; + case INSTRUMENTED_END_FOR: + return 2; + case END_SEND: + return 2; + case INSTRUMENTED_END_SEND: + return 2; case UNARY_NEGATIVE: return 1; case UNARY_NOT: @@ -97,8 +105,12 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 1; case RETURN_VALUE: return 1; + case INSTRUMENTED_RETURN_VALUE: + return 1; case RETURN_CONST: return 0; + case INSTRUMENTED_RETURN_CONST: + return 0; case GET_AITER: return 1; case GET_ANEXT: @@ -109,6 +121,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 2; case SEND_GEN: return 2; + case INSTRUMENTED_YIELD_VALUE: + return 1; case YIELD_VALUE: return 1; case POP_EXCEPT: @@ -263,6 +277,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 1; case FOR_ITER: return 1; + case INSTRUMENTED_FOR_ITER: + return 0; case FOR_ITER_LIST: return 1; case FOR_ITER_TUPLE: @@ -287,6 +303,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 1; case KW_NAMES: return 0; + case INSTRUMENTED_CALL: + return 0; case CALL: return oparg + 2; case CALL_BOUND_METHOD_EXACT_ARGS: @@ -323,6 +341,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return oparg + 2; case CALL_NO_KW_METHOD_DESCRIPTOR_FAST: return oparg + 2; + case INSTRUMENTED_CALL_FUNCTION_EX: + return 0; case CALL_FUNCTION_EX: return ((oparg & 1) ? 1 : 0) + 3; case MAKE_FUNCTION: @@ -339,10 +359,28 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 2; case SWAP: return (oparg-2) + 2; + case INSTRUMENTED_LINE: + return 0; + case INSTRUMENTED_INSTRUCTION: + return 0; + case INSTRUMENTED_JUMP_FORWARD: + return 0; + case INSTRUMENTED_JUMP_BACKWARD: + return 0; + case INSTRUMENTED_POP_JUMP_IF_TRUE: + return 0; + case INSTRUMENTED_POP_JUMP_IF_FALSE: + return 0; + case INSTRUMENTED_POP_JUMP_IF_NONE: + return 0; + case INSTRUMENTED_POP_JUMP_IF_NOT_NONE: + return 0; case EXTENDED_ARG: return 0; case CACHE: return 0; + case RESERVED: + return 0; default: return -1; } @@ -359,6 +397,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case RESUME: return 0; + case INSTRUMENTED_RESUME: + return 0; case LOAD_CLOSURE: return 1; case LOAD_FAST_CHECK: @@ -385,6 +425,12 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 1; case END_FOR: return 0+0; + case INSTRUMENTED_END_FOR: + return 0; + case END_SEND: + return 1; + case INSTRUMENTED_END_SEND: + return 1; case UNARY_NEGATIVE: return 1; case UNARY_NOT: @@ -443,8 +489,12 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case RETURN_VALUE: return 0; + case INSTRUMENTED_RETURN_VALUE: + return 0; case RETURN_CONST: return 0; + case INSTRUMENTED_RETURN_CONST: + return 0; case GET_AITER: return 1; case GET_ANEXT: @@ -455,6 +505,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 2; case SEND_GEN: return 1; + case INSTRUMENTED_YIELD_VALUE: + return 1; case YIELD_VALUE: return 1; case POP_EXCEPT: @@ -609,6 +661,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 1; case FOR_ITER: return 2; + case INSTRUMENTED_FOR_ITER: + return 0; case FOR_ITER_LIST: return 2; case FOR_ITER_TUPLE: @@ -633,6 +687,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return ((oparg & 1) ? 1 : 0) + 1; case KW_NAMES: return 0; + case INSTRUMENTED_CALL: + return 0; case CALL: return 1; case CALL_BOUND_METHOD_EXACT_ARGS: @@ -669,6 +725,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 1; case CALL_NO_KW_METHOD_DESCRIPTOR_FAST: return 1; + case INSTRUMENTED_CALL_FUNCTION_EX: + return 0; case CALL_FUNCTION_EX: return 1; case MAKE_FUNCTION: @@ -685,10 +743,28 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 1; case SWAP: return (oparg-2) + 2; + case INSTRUMENTED_LINE: + return 0; + case INSTRUMENTED_INSTRUCTION: + return 0; + case INSTRUMENTED_JUMP_FORWARD: + return 0; + case INSTRUMENTED_JUMP_BACKWARD: + return 0; + case INSTRUMENTED_POP_JUMP_IF_TRUE: + return 0; + case INSTRUMENTED_POP_JUMP_IF_FALSE: + return 0; + case INSTRUMENTED_POP_JUMP_IF_NONE: + return 0; + case INSTRUMENTED_POP_JUMP_IF_NOT_NONE: + return 0; case EXTENDED_ARG: return 0; case CACHE: return 0; + case RESERVED: + return 0; default: return -1; } @@ -707,6 +783,7 @@ extern const struct opcode_metadata _PyOpcode_opcode_metadata[256]; const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [NOP] = { true, INSTR_FMT_IX }, [RESUME] = { true, INSTR_FMT_IB }, + [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB }, [LOAD_CLOSURE] = { true, INSTR_FMT_IB }, [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB }, [LOAD_FAST] = { true, INSTR_FMT_IB }, @@ -720,6 +797,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [POP_TOP] = { true, INSTR_FMT_IX }, [PUSH_NULL] = { true, INSTR_FMT_IX }, [END_FOR] = { true, INSTR_FMT_IB }, + [INSTRUMENTED_END_FOR] = { true, INSTR_FMT_IX }, + [END_SEND] = { true, INSTR_FMT_IX }, + [INSTRUMENTED_END_SEND] = { true, INSTR_FMT_IX }, [UNARY_NEGATIVE] = { true, INSTR_FMT_IX }, [UNARY_NOT] = { true, INSTR_FMT_IX }, [UNARY_INVERT] = { true, INSTR_FMT_IX }, @@ -749,12 +829,15 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [RAISE_VARARGS] = { true, INSTR_FMT_IB }, [INTERPRETER_EXIT] = { true, INSTR_FMT_IX }, [RETURN_VALUE] = { true, INSTR_FMT_IX }, + [INSTRUMENTED_RETURN_VALUE] = { true, INSTR_FMT_IX }, [RETURN_CONST] = { true, INSTR_FMT_IB }, + [INSTRUMENTED_RETURN_CONST] = { true, INSTR_FMT_IB }, [GET_AITER] = { true, INSTR_FMT_IX }, [GET_ANEXT] = { true, INSTR_FMT_IX }, [GET_AWAITABLE] = { true, INSTR_FMT_IB }, [SEND] = { true, INSTR_FMT_IBC }, [SEND_GEN] = { true, INSTR_FMT_IBC }, + [INSTRUMENTED_YIELD_VALUE] = { true, INSTR_FMT_IX }, [YIELD_VALUE] = { true, INSTR_FMT_IX }, [POP_EXCEPT] = { true, INSTR_FMT_IX }, [RERAISE] = { true, INSTR_FMT_IB }, @@ -832,6 +915,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [GET_ITER] = { true, INSTR_FMT_IX }, [GET_YIELD_FROM_ITER] = { true, INSTR_FMT_IX }, [FOR_ITER] = { true, INSTR_FMT_IBC }, + [INSTRUMENTED_FOR_ITER] = { true, INSTR_FMT_IB }, [FOR_ITER_LIST] = { true, INSTR_FMT_IBC }, [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC }, [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC }, @@ -844,6 +928,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000 }, [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000 }, [KW_NAMES] = { true, INSTR_FMT_IB }, + [INSTRUMENTED_CALL] = { true, INSTR_FMT_IB }, [CALL] = { true, INSTR_FMT_IBC00 }, [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00 }, [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00 }, @@ -862,6 +947,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00 }, [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00 }, [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00 }, + [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX }, [CALL_FUNCTION_EX] = { true, INSTR_FMT_IB }, [MAKE_FUNCTION] = { true, INSTR_FMT_IB }, [RETURN_GENERATOR] = { true, INSTR_FMT_IX }, @@ -870,7 +956,16 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [COPY] = { true, INSTR_FMT_IB }, [BINARY_OP] = { true, INSTR_FMT_IBC }, [SWAP] = { true, INSTR_FMT_IB }, + [INSTRUMENTED_LINE] = { true, INSTR_FMT_IX }, + [INSTRUMENTED_INSTRUCTION] = { true, INSTR_FMT_IX }, + [INSTRUMENTED_JUMP_FORWARD] = { true, INSTR_FMT_IB }, + [INSTRUMENTED_JUMP_BACKWARD] = { true, INSTR_FMT_IB }, + [INSTRUMENTED_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB }, + [INSTRUMENTED_POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB }, + [INSTRUMENTED_POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB }, + [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB }, [EXTENDED_ARG] = { true, INSTR_FMT_IB }, [CACHE] = { true, INSTR_FMT_IX }, + [RESERVED] = { true, INSTR_FMT_IX }, }; #endif diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index c502471bcd17..9d6616666f7a 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -4,17 +4,19 @@ static void *opcode_targets[256] = { &&TARGET_PUSH_NULL, &&TARGET_INTERPRETER_EXIT, &&TARGET_END_FOR, + &&TARGET_END_SEND, &&TARGET_BINARY_OP_ADD_FLOAT, &&TARGET_BINARY_OP_ADD_INT, &&TARGET_BINARY_OP_ADD_UNICODE, - &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, &&TARGET_NOP, - &&TARGET_BINARY_OP_MULTIPLY_FLOAT, + &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, &&TARGET_UNARY_NEGATIVE, &&TARGET_UNARY_NOT, + &&TARGET_BINARY_OP_MULTIPLY_FLOAT, &&TARGET_BINARY_OP_MULTIPLY_INT, - &&TARGET_BINARY_OP_SUBTRACT_FLOAT, &&TARGET_UNARY_INVERT, + &&TARGET_BINARY_OP_SUBTRACT_FLOAT, + &&TARGET_RESERVED, &&TARGET_BINARY_OP_SUBTRACT_INT, &&TARGET_BINARY_SUBSCR_DICT, &&TARGET_BINARY_SUBSCR_GETITEM, @@ -22,21 +24,21 @@ static void *opcode_targets[256] = { &&TARGET_BINARY_SUBSCR_TUPLE_INT, &&TARGET_CALL_PY_EXACT_ARGS, &&TARGET_CALL_PY_WITH_DEFAULTS, - &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, - &&TARGET_CALL_BUILTIN_CLASS, &&TARGET_BINARY_SUBSCR, &&TARGET_BINARY_SLICE, &&TARGET_STORE_SLICE, - &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, - &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, + &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, + &&TARGET_CALL_BUILTIN_CLASS, &&TARGET_GET_LEN, &&TARGET_MATCH_MAPPING, &&TARGET_MATCH_SEQUENCE, &&TARGET_MATCH_KEYS, - &&TARGET_CALL_NO_KW_BUILTIN_FAST, + &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, &&TARGET_PUSH_EXC_INFO, &&TARGET_CHECK_EXC_MATCH, &&TARGET_CHECK_EG_MATCH, + &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, + &&TARGET_CALL_NO_KW_BUILTIN_FAST, &&TARGET_CALL_NO_KW_BUILTIN_O, &&TARGET_CALL_NO_KW_ISINSTANCE, &&TARGET_CALL_NO_KW_LEN, @@ -46,8 +48,6 @@ static void *opcode_targets[256] = { &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, &&TARGET_CALL_NO_KW_STR_1, &&TARGET_CALL_NO_KW_TUPLE_1, - &&TARGET_CALL_NO_KW_TYPE_1, - &&TARGET_COMPARE_OP_FLOAT, &&TARGET_WITH_EXCEPT_START, &&TARGET_GET_AITER, &&TARGET_GET_ANEXT, @@ -55,39 +55,39 @@ static void *opcode_targets[256] = { &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, &&TARGET_CLEANUP_THROW, + &&TARGET_CALL_NO_KW_TYPE_1, + &&TARGET_COMPARE_OP_FLOAT, &&TARGET_COMPARE_OP_INT, &&TARGET_COMPARE_OP_STR, - &&TARGET_FOR_ITER_LIST, - &&TARGET_FOR_ITER_TUPLE, &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, + &&TARGET_FOR_ITER_LIST, + &&TARGET_FOR_ITER_TUPLE, &&TARGET_FOR_ITER_RANGE, &&TARGET_FOR_ITER_GEN, &&TARGET_LOAD_ATTR_CLASS, &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, - &&TARGET_LOAD_ATTR_INSTANCE_VALUE, - &&TARGET_LOAD_ATTR_MODULE, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, - &&TARGET_LOAD_ATTR_PROPERTY, + &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_BUILD_CLASS, - &&TARGET_LOAD_ATTR_SLOT, - &&TARGET_LOAD_ATTR_WITH_HINT, + &&TARGET_LOAD_ATTR_MODULE, + &&TARGET_LOAD_ATTR_PROPERTY, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, + &&TARGET_LOAD_ATTR_SLOT, + &&TARGET_LOAD_ATTR_WITH_HINT, &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, &&TARGET_LOAD_ATTR_METHOD_NO_DICT, &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_LOAD_FAST__LOAD_CONST, + &&TARGET_RETURN_VALUE, &&TARGET_LOAD_FAST__LOAD_FAST, + &&TARGET_SETUP_ANNOTATIONS, &&TARGET_LOAD_GLOBAL_BUILTIN, - &&TARGET_RETURN_VALUE, &&TARGET_LOAD_GLOBAL_MODULE, - &&TARGET_SETUP_ANNOTATIONS, &&TARGET_STORE_ATTR_INSTANCE_VALUE, - &&TARGET_STORE_ATTR_SLOT, - &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_POP_EXCEPT, &&TARGET_STORE_NAME, &&TARGET_DELETE_NAME, @@ -110,9 +110,9 @@ static void *opcode_targets[256] = { &&TARGET_IMPORT_NAME, &&TARGET_IMPORT_FROM, &&TARGET_JUMP_FORWARD, + &&TARGET_STORE_ATTR_SLOT, + &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_FAST__LOAD_FAST, - &&TARGET_STORE_FAST__STORE_FAST, - &&TARGET_STORE_SUBSCR_DICT, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -140,9 +140,9 @@ static void *opcode_targets[256] = { &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, &&TARGET_JUMP_BACKWARD, - &&TARGET_STORE_SUBSCR_LIST_INT, + &&TARGET_STORE_FAST__STORE_FAST, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_UNPACK_SEQUENCE_LIST, + &&TARGET_STORE_SUBSCR_DICT, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,15 +152,15 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, - &&TARGET_UNPACK_SEQUENCE_TUPLE, - &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, + &&TARGET_STORE_SUBSCR_LIST_INT, + &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, + &&TARGET_UNPACK_SEQUENCE_TUPLE, + &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_SEND_GEN, &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, @@ -237,22 +237,22 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&TARGET_DO_TRACING + &&TARGET_INSTRUMENTED_POP_JUMP_IF_NONE, + &&TARGET_INSTRUMENTED_POP_JUMP_IF_NOT_NONE, + &&TARGET_INSTRUMENTED_RESUME, + &&TARGET_INSTRUMENTED_CALL, + &&TARGET_INSTRUMENTED_RETURN_VALUE, + &&TARGET_INSTRUMENTED_YIELD_VALUE, + &&TARGET_INSTRUMENTED_CALL_FUNCTION_EX, + &&TARGET_INSTRUMENTED_JUMP_FORWARD, + &&TARGET_INSTRUMENTED_JUMP_BACKWARD, + &&TARGET_INSTRUMENTED_RETURN_CONST, + &&TARGET_INSTRUMENTED_FOR_ITER, + &&TARGET_INSTRUMENTED_POP_JUMP_IF_FALSE, + &&TARGET_INSTRUMENTED_POP_JUMP_IF_TRUE, + &&TARGET_INSTRUMENTED_END_FOR, + &&TARGET_INSTRUMENTED_END_SEND, + &&TARGET_INSTRUMENTED_INSTRUCTION, + &&TARGET_INSTRUMENTED_LINE, + &&_unknown_opcode }; diff --git a/Python/pystate.c b/Python/pystate.c index 37cef972e0fe..1e04887ef04a 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -625,7 +625,6 @@ free_interpreter(PyInterpreterState *interp) main interpreter. We fix those fields here, in addition to the other dynamically initialized fields. */ - static void init_interpreter(PyInterpreterState *interp, _PyRuntimeState *runtime, int64_t id, @@ -650,12 +649,22 @@ init_interpreter(PyInterpreterState *interp, _PyGC_InitState(&interp->gc); PyConfig_InitPythonConfig(&interp->config); _PyType_InitCache(interp); + for(int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { + interp->monitors.tools[i] = 0; + } + for (int t = 0; t < PY_MONITORING_TOOL_IDS; t++) { + for(int e = 0; e < PY_MONITORING_EVENTS; e++) { + interp->monitoring_callables[t][e] = NULL; + } + } + interp->sys_profile_initialized = false; + interp->sys_trace_initialized = false; if (interp != &runtime->_main_interpreter) { /* Fix the self-referential, statically initialized fields. */ interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp); } - + interp->f_opcode_trace_set = false; interp->_initialized = 1; } @@ -788,6 +797,20 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) Py_CLEAR(interp->audit_hooks); + for(int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { + interp->monitors.tools[i] = 0; + } + for (int t = 0; t < PY_MONITORING_TOOL_IDS; t++) { + for(int e = 0; e < PY_MONITORING_EVENTS; e++) { + Py_CLEAR(interp->monitoring_callables[t][e]); + } + } + interp->sys_profile_initialized = false; + interp->sys_trace_initialized = false; + for (int t = 0; t < PY_MONITORING_TOOL_IDS; t++) { + Py_CLEAR(interp->monitoring_tool_names[t]); + } + PyConfig_Clear(&interp->config); Py_CLEAR(interp->codec_search_path); Py_CLEAR(interp->codec_search_cache); @@ -845,7 +868,7 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) interp->code_watchers[i] = NULL; } interp->active_code_watchers = 0; - + interp->f_opcode_trace_set = false; // XXX Once we have one allocator per interpreter (i.e. // per-interpreter GC) we must ensure that all of the interpreter's // objects have been cleaned up at the point. @@ -1237,6 +1260,7 @@ init_threadstate(PyThreadState *tstate, tstate->datastack_chunk = NULL; tstate->datastack_top = NULL; tstate->datastack_limit = NULL; + tstate->what_event = -1; tstate->_status.initialized = 1; } @@ -1412,8 +1436,14 @@ PyThreadState_Clear(PyThreadState *tstate) "PyThreadState_Clear: warning: thread still has a generator\n"); } - tstate->c_profilefunc = NULL; - tstate->c_tracefunc = NULL; + if (tstate->c_profilefunc != NULL) { + tstate->interp->sys_profiling_threads--; + tstate->c_profilefunc = NULL; + } + if (tstate->c_tracefunc != NULL) { + tstate->interp->sys_tracing_threads--; + tstate->c_tracefunc = NULL; + } Py_CLEAR(tstate->c_profileobj); Py_CLEAR(tstate->c_traceobj); diff --git a/Python/specialize.c b/Python/specialize.c index a9d3226ee39f..3fa28f409892 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -273,7 +273,8 @@ _PyCode_Quicken(PyCodeObject *code) _Py_CODEUNIT *instructions = _PyCode_CODE(code); for (int i = 0; i < Py_SIZE(code); i++) { int previous_opcode = opcode; - opcode = _PyOpcode_Deopt[instructions[i].op.code]; + opcode = _Py_GetBaseOpcode(code, i); + assert(opcode < MIN_INSTRUMENTED_OPCODE); int caches = _PyOpcode_Caches[opcode]; if (caches) { instructions[i + 1].cache = adaptive_counter_warmup(); @@ -1737,6 +1738,7 @@ _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, { assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[CALL] == INLINE_CACHE_ENTRIES_CALL); + assert(_Py_OPCODE(*instr) != INSTRUMENTED_CALL); _PyCallCache *cache = (_PyCallCache *)(instr + 1); int fail; if (PyCFunction_CheckExact(callable)) { @@ -2149,7 +2151,9 @@ _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg) goto success; } else if (tp == &PyGen_Type && oparg <= SHRT_MAX) { - assert(instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1].op.code == END_FOR); + assert(instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1].op.code == END_FOR || + instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1].op.code == INSTRUMENTED_END_FOR + ); instr->op.code = FOR_ITER_GEN; goto success; } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index f1a294de5984..4d693a1be1f8 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3409,6 +3409,7 @@ _PySys_SetPreliminaryStderr(PyObject *sysdict) return _PyStatus_ERR("can't set preliminary stderr"); } +PyObject *_Py_CreateMonitoringObject(void); /* Create sys module without all attributes. _PySys_UpdateConfig() should be called later to add remaining attributes. */ @@ -3458,6 +3459,16 @@ _PySys_Create(PyThreadState *tstate, PyObject **sysmod_p) goto error; } + PyObject *monitoring = _Py_CreateMonitoringObject(); + if (monitoring == NULL) { + goto error; + } + int err = PyDict_SetItemString(sysdict, "monitoring", monitoring); + Py_DECREF(monitoring); + if (err < 0) { + goto error; + } + assert(!_PyErr_Occurred(tstate)); *sysmod_p = sysmod; diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py index ec808526b7bb..aba5fecd8b1a 100644 --- a/Tools/build/deepfreeze.py +++ b/Tools/build/deepfreeze.py @@ -255,7 +255,6 @@ def generate_code(self, name: str, code: types.CodeType) -> str: self.write(f".co_names = {co_names},") self.write(f".co_exceptiontable = {co_exceptiontable},") self.field(code, "co_flags") - self.write("._co_linearray_entry_size = 0,") self.field(code, "co_argcount") self.field(code, "co_posonlyargcount") self.field(code, "co_kwonlyargcount") @@ -276,7 +275,6 @@ def generate_code(self, name: str, code: types.CodeType) -> str: self.write(f".co_qualname = {co_qualname},") self.write(f".co_linetable = {co_linetable},") self.write(f"._co_cached = NULL,") - self.write("._co_linearray = NULL,") self.write(f".co_code_adaptive = {co_code_adaptive},") for i, op in enumerate(code.co_code[::2]): if op == RESUME: diff --git a/Tools/build/generate_opcode_h.py b/Tools/build/generate_opcode_h.py index 12fdd3ac84b3..645b9f1de117 100644 --- a/Tools/build/generate_opcode_h.py +++ b/Tools/build/generate_opcode_h.py @@ -89,6 +89,7 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna HAVE_ARGUMENT = opcode["HAVE_ARGUMENT"] MIN_PSEUDO_OPCODE = opcode["MIN_PSEUDO_OPCODE"] MAX_PSEUDO_OPCODE = opcode["MAX_PSEUDO_OPCODE"] + MIN_INSTRUMENTED_OPCODE = opcode["MIN_INSTRUMENTED_OPCODE"] NUM_OPCODES = len(opname) used = [ False ] * len(opname) @@ -105,9 +106,6 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna specialized_opmap[name] = next_op opname_including_specialized[next_op] = name used[next_op] = True - specialized_opmap['DO_TRACING'] = 255 - opname_including_specialized[255] = 'DO_TRACING' - used[255] = True with open(outfile, 'w') as fobj, open(internaloutfile, 'w') as iobj: fobj.write(header) @@ -120,6 +118,8 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna fobj.write(DEFINE.format("HAVE_ARGUMENT", HAVE_ARGUMENT)) if op == MIN_PSEUDO_OPCODE: fobj.write(DEFINE.format("MIN_PSEUDO_OPCODE", MIN_PSEUDO_OPCODE)) + if op == MIN_INSTRUMENTED_OPCODE: + fobj.write(DEFINE.format("MIN_INSTRUMENTED_OPCODE", MIN_INSTRUMENTED_OPCODE)) fobj.write(DEFINE.format(name, op)) diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index e36024ad16c2..823340ecc491 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -135,6 +135,9 @@ Objects/stringlib/unicode_format.h - PyFieldNameIter_Type - Objects/unicodeobject.c - EncodingMapType - #Objects/unicodeobject.c - PyFieldNameIter_Type - #Objects/unicodeobject.c - PyFormatterIter_Type - +Python/legacy_tracing.c - _PyLegacyEventHandler_Type - +Objects/object.c - _PyLegacyEventHandler_Type - + ##----------------------- ## static builtin structseq @@ -297,6 +300,8 @@ Objects/object.c - _Py_NotImplementedStruct - Objects/setobject.c - _dummy_struct - Objects/setobject.c - _PySet_Dummy - Objects/sliceobject.c - _Py_EllipsisObject - +Python/instrumentation.c - DISABLE - +Python/instrumentation.c - _PyInstrumentation_MISSING - ################################## From webhook-mailer at python.org Wed Apr 12 08:51:36 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Wed, 12 Apr 2023 12:51:36 -0000 Subject: [Python-checkins] gh-103092: Isolate `_collections` (#103093) Message-ID: https://github.com/python/cpython/commit/52f96d3ea39fea4c16e26b7b10bd2db09726bd7c commit: 52f96d3ea39fea4c16e26b7b10bd2db09726bd7c branch: main author: Erlend E. Aasland committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-04-12T18:21:28+05:30 summary: gh-103092: Isolate `_collections` (#103093) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2023-04-09-06-59-36.gh-issue-103092.vskbro.rst M Lib/collections/__init__.py M Modules/_collectionsmodule.c M Modules/clinic/_collectionsmodule.c.h M Tools/c-analyzer/cpython/globals-to-fix.tsv diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py index a5393aad4249..03ca2d7e18f6 100644 --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -45,6 +45,11 @@ else: _collections_abc.MutableSequence.register(deque) +try: + from _collections import _deque_iterator +except ImportError: + pass + try: from _collections import defaultdict except ImportError: diff --git a/Misc/NEWS.d/next/Library/2023-04-09-06-59-36.gh-issue-103092.vskbro.rst b/Misc/NEWS.d/next/Library/2023-04-09-06-59-36.gh-issue-103092.vskbro.rst new file mode 100644 index 000000000000..6977c1489a29 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-09-06-59-36.gh-issue-103092.vskbro.rst @@ -0,0 +1 @@ +Isolate :mod:`!_collections` (apply :pep:`687`). Patch by Erlend E. Aasland. diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 9d8aef1e6771..a9b1425177c3 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -1,17 +1,56 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_long.h" // _PyLong_GetZero() +#include "pycore_moduleobject.h" // _PyModule_GetState() +#include "pycore_typeobject.h" // _PyType_GetModuleState() #include "structmember.h" // PyMemberDef #include +typedef struct { + PyTypeObject *deque_type; + PyTypeObject *defdict_type; + PyTypeObject *dequeiter_type; + PyTypeObject *dequereviter_type; + PyTypeObject *tuplegetter_type; +} collections_state; + +static inline collections_state * +get_module_state(PyObject *mod) +{ + void *state = _PyModule_GetState(mod); + assert(state != NULL); + return (collections_state *)state; +} + +static inline collections_state * +get_module_state_by_cls(PyTypeObject *cls) +{ + void *state = _PyType_GetModuleState(cls); + assert(state != NULL); + return (collections_state *)state; +} + +static struct PyModuleDef _collectionsmodule; + +static inline collections_state * +find_module_state_by_def(PyTypeObject *type) +{ + PyObject *mod = PyType_GetModuleByDef(type, &_collectionsmodule); + assert(mod != NULL); + return get_module_state(mod); +} + /*[clinic input] module _collections -class _tuplegetter "_tuplegetterobject *" "&tuplegetter_type" +class _tuplegetter "_tuplegetterobject *" "clinic_state()->tuplegetter_type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a8ece4ccad7e30ac]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=7356042a89862e0e]*/ -static PyTypeObject tuplegetter_type; +/* We can safely assume type to be the defining class, + * since tuplegetter is not a base type */ +#define clinic_state() (get_module_state_by_cls(type)) #include "clinic/_collectionsmodule.c.h" +#undef clinic_state /* collections module implementation of a deque() datatype Written and maintained by Raymond D. Hettinger @@ -94,8 +133,6 @@ typedef struct { PyObject *weakreflist; } dequeobject; -static PyTypeObject deque_type; - /* For debug builds, add error checking to track the endpoints * in the chain of links. The goal is to make sure that link * assignments only take place at endpoints so that links already @@ -484,11 +521,13 @@ deque_copy(PyObject *deque, PyObject *Py_UNUSED(ignored)) { PyObject *result; dequeobject *old_deque = (dequeobject *)deque; - if (Py_IS_TYPE(deque, &deque_type)) { + collections_state *state = find_module_state_by_def(Py_TYPE(deque)); + if (Py_IS_TYPE(deque, state->deque_type)) { dequeobject *new_deque; PyObject *rv; - new_deque = (dequeobject *)deque_new(&deque_type, (PyObject *)NULL, (PyObject *)NULL); + new_deque = (dequeobject *)deque_new(state->deque_type, + (PyObject *)NULL, (PyObject *)NULL); if (new_deque == NULL) return NULL; new_deque->maxlen = old_deque->maxlen; @@ -511,7 +550,7 @@ deque_copy(PyObject *deque, PyObject *Py_UNUSED(ignored)) else result = PyObject_CallFunction((PyObject *)(Py_TYPE(deque)), "Oi", deque, old_deque->maxlen, NULL); - if (result != NULL && !PyObject_TypeCheck(result, &deque_type)) { + if (result != NULL && !PyObject_TypeCheck(result, state->deque_type)) { PyErr_Format(PyExc_TypeError, "%.200s() must return a deque, not %.200s", Py_TYPE(deque)->tp_name, Py_TYPE(result)->tp_name); @@ -529,7 +568,8 @@ deque_concat(dequeobject *deque, PyObject *other) PyObject *new_deque, *result; int rv; - rv = PyObject_IsInstance(other, (PyObject *)&deque_type); + collections_state *state = find_module_state_by_def(Py_TYPE(deque)); + rv = PyObject_IsInstance(other, (PyObject *)state->deque_type); if (rv <= 0) { if (rv == 0) { PyErr_Format(PyExc_TypeError, @@ -1288,6 +1328,7 @@ deque_ass_item(dequeobject *deque, Py_ssize_t i, PyObject *v) static void deque_dealloc(dequeobject *deque) { + PyTypeObject *tp = Py_TYPE(deque); Py_ssize_t i; PyObject_GC_UnTrack(deque); @@ -1303,12 +1344,15 @@ deque_dealloc(dequeobject *deque) for (i=0 ; i < deque->numfreeblocks ; i++) { PyMem_Free(deque->freeblocks[i]); } - Py_TYPE(deque)->tp_free(deque); + tp->tp_free(deque); + Py_DECREF(tp); } static int deque_traverse(dequeobject *deque, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(deque)); + block *b; PyObject *item; Py_ssize_t index; @@ -1393,8 +1437,9 @@ deque_richcompare(PyObject *v, PyObject *w, int op) Py_ssize_t vs, ws; int b, cmp=-1; - if (!PyObject_TypeCheck(v, &deque_type) || - !PyObject_TypeCheck(w, &deque_type)) { + collections_state *state = find_module_state_by_def(Py_TYPE(v)); + if (!PyObject_TypeCheck(v, state->deque_type) || + !PyObject_TypeCheck(w, state->deque_type)) { Py_RETURN_NOTIMPLEMENTED; } @@ -1537,19 +1582,6 @@ static PyGetSetDef deque_getset[] = { {0} }; -static PySequenceMethods deque_as_sequence = { - (lenfunc)deque_len, /* sq_length */ - (binaryfunc)deque_concat, /* sq_concat */ - (ssizeargfunc)deque_repeat, /* sq_repeat */ - (ssizeargfunc)deque_item, /* sq_item */ - 0, /* sq_slice */ - (ssizeobjargproc)deque_ass_item, /* sq_ass_item */ - 0, /* sq_ass_slice */ - (objobjproc)deque_contains, /* sq_contains */ - (binaryfunc)deque_inplace_concat, /* sq_inplace_concat */ - (ssizeargfunc)deque_inplace_repeat, /* sq_inplace_repeat */ -}; - static PyObject *deque_iter(dequeobject *deque); static PyObject *deque_reviter(dequeobject *deque, PyObject *Py_UNUSED(ignored)); PyDoc_STRVAR(reversed_doc, @@ -1597,54 +1629,53 @@ static PyMethodDef deque_methods[] = { {NULL, NULL} /* sentinel */ }; +static PyMemberDef deque_members[] = { + {"__weaklistoffset__", T_PYSSIZET, offsetof(dequeobject, weakreflist), READONLY}, + {NULL}, +}; + PyDoc_STRVAR(deque_doc, "deque([iterable[, maxlen]]) --> deque object\n\ \n\ A list-like sequence optimized for data accesses near its endpoints."); -static PyTypeObject deque_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "collections.deque", /* tp_name */ - sizeof(dequeobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)deque_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - deque_repr, /* tp_repr */ - 0, /* tp_as_number */ - &deque_as_sequence, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - PyObject_HashNotImplemented, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_SEQUENCE, - /* tp_flags */ - deque_doc, /* tp_doc */ - (traverseproc)deque_traverse, /* tp_traverse */ - (inquiry)deque_clear, /* tp_clear */ - (richcmpfunc)deque_richcompare, /* tp_richcompare */ - offsetof(dequeobject, weakreflist), /* tp_weaklistoffset*/ - (getiterfunc)deque_iter, /* tp_iter */ - 0, /* tp_iternext */ - deque_methods, /* tp_methods */ - 0, /* tp_members */ - deque_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)deque_init, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - deque_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyType_Slot deque_slots[] = { + {Py_tp_dealloc, deque_dealloc}, + {Py_tp_repr, deque_repr}, + {Py_tp_hash, PyObject_HashNotImplemented}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)deque_doc}, + {Py_tp_traverse, deque_traverse}, + {Py_tp_clear, deque_clear}, + {Py_tp_richcompare, deque_richcompare}, + {Py_tp_iter, deque_iter}, + {Py_tp_getset, deque_getset}, + {Py_tp_init, deque_init}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_new, deque_new}, + {Py_tp_free, PyObject_GC_Del}, + {Py_tp_methods, deque_methods}, + {Py_tp_members, deque_members}, + + // Sequence protocol + {Py_sq_length, deque_len}, + {Py_sq_concat, deque_concat}, + {Py_sq_repeat, deque_repeat}, + {Py_sq_item, deque_item}, + {Py_sq_ass_item, deque_ass_item}, + {Py_sq_contains, deque_contains}, + {Py_sq_inplace_concat, deque_inplace_concat}, + {Py_sq_inplace_repeat, deque_inplace_repeat}, + {0, NULL}, +}; + +static PyType_Spec deque_spec = { + .name = "collections.deque", + .basicsize = sizeof(dequeobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_SEQUENCE | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = deque_slots, }; /*********************** Deque Iterator **************************/ @@ -1658,14 +1689,13 @@ typedef struct { Py_ssize_t counter; /* number of items remaining for iteration */ } dequeiterobject; -static PyTypeObject dequeiter_type; - static PyObject * deque_iter(dequeobject *deque) { dequeiterobject *it; - it = PyObject_GC_New(dequeiterobject, &dequeiter_type); + collections_state *state = find_module_state_by_def(Py_TYPE(deque)); + it = PyObject_GC_New(dequeiterobject, state->dequeiter_type); if (it == NULL) return NULL; it->b = deque->leftblock; @@ -1680,17 +1710,27 @@ deque_iter(dequeobject *deque) static int dequeiter_traverse(dequeiterobject *dio, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(dio)); Py_VISIT(dio->deque); return 0; } +static int +dequeiter_clear(dequeiterobject *dio) +{ + Py_CLEAR(dio->deque); + return 0; +} + static void dequeiter_dealloc(dequeiterobject *dio) { /* bpo-31095: UnTrack is needed before calling any callbacks */ + PyTypeObject *tp = Py_TYPE(dio); PyObject_GC_UnTrack(dio); - Py_XDECREF(dio->deque); + (void)dequeiter_clear(dio); PyObject_GC_Del(dio); + Py_DECREF(tp); } static PyObject * @@ -1726,9 +1766,10 @@ dequeiter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) Py_ssize_t i, index=0; PyObject *deque; dequeiterobject *it; - if (!PyArg_ParseTuple(args, "O!|n", &deque_type, &deque, &index)) + collections_state *state = get_module_state_by_cls(type); + if (!PyArg_ParseTuple(args, "O!|n", state->deque_type, &deque, &index)) return NULL; - assert(type == &dequeiter_type); + assert(type == state->dequeiter_type); it = (dequeiterobject*)deque_iter((dequeobject *)deque); if (!it) @@ -1769,59 +1810,35 @@ static PyMethodDef dequeiter_methods[] = { {NULL, NULL} /* sentinel */ }; -static PyTypeObject dequeiter_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_collections._deque_iterator", /* tp_name */ - sizeof(dequeiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)dequeiter_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)dequeiter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)dequeiter_next, /* tp_iternext */ - dequeiter_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - dequeiter_new, /* tp_new */ - 0, +static PyType_Slot dequeiter_slots[] = { + {Py_tp_dealloc, dequeiter_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_traverse, dequeiter_traverse}, + {Py_tp_clear, dequeiter_clear}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, dequeiter_next}, + {Py_tp_methods, dequeiter_methods}, + {Py_tp_new, dequeiter_new}, + {0, NULL}, }; -/*********************** Deque Reverse Iterator **************************/ +static PyType_Spec dequeiter_spec = { + .name = "collections._deque_iterator", + .basicsize = sizeof(dequeiterobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = dequeiter_slots, +}; -static PyTypeObject dequereviter_type; +/*********************** Deque Reverse Iterator **************************/ static PyObject * deque_reviter(dequeobject *deque, PyObject *Py_UNUSED(ignored)) { dequeiterobject *it; + collections_state *state = find_module_state_by_def(Py_TYPE(deque)); - it = PyObject_GC_New(dequeiterobject, &dequereviter_type); + it = PyObject_GC_New(dequeiterobject, state->dequereviter_type); if (it == NULL) return NULL; it->b = deque->rightblock; @@ -1866,9 +1883,10 @@ dequereviter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) Py_ssize_t i, index=0; PyObject *deque; dequeiterobject *it; - if (!PyArg_ParseTuple(args, "O!|n", &deque_type, &deque, &index)) + collections_state *state = get_module_state_by_cls(type); + if (!PyArg_ParseTuple(args, "O!|n", state->deque_type, &deque, &index)) return NULL; - assert(type == &dequereviter_type); + assert(type == state->dequereviter_type); it = (dequeiterobject*)deque_reviter((dequeobject *)deque, NULL); if (!it) @@ -1889,47 +1907,24 @@ dequereviter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject*)it; } -static PyTypeObject dequereviter_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_collections._deque_reverse_iterator", /* tp_name */ - sizeof(dequeiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)dequeiter_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)dequeiter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)dequereviter_next, /* tp_iternext */ - dequeiter_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - dequereviter_new, /* tp_new */ - 0, +static PyType_Slot dequereviter_slots[] = { + {Py_tp_dealloc, dequeiter_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_traverse, dequeiter_traverse}, + {Py_tp_clear, dequeiter_clear}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, dequereviter_next}, + {Py_tp_methods, dequeiter_methods}, + {Py_tp_new, dequereviter_new}, + {0, NULL}, +}; + +static PyType_Spec dequereviter_spec = { + .name = "collections._deque_reverse_iterator", + .basicsize = sizeof(dequeiterobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = dequereviter_slots, }; /* defaultdict type *********************************************************/ @@ -1939,8 +1934,6 @@ typedef struct { PyObject *default_factory; } defdictobject; -static PyTypeObject defdict_type; /* Forward */ - PyDoc_STRVAR(defdict_missing_doc, "__missing__(key) # Called by __getitem__ for missing key; pseudo-code:\n\ if self.default_factory is None: raise KeyError((key,))\n\ @@ -2071,9 +2064,11 @@ static void defdict_dealloc(defdictobject *dd) { /* bpo-31095: UnTrack is needed before calling any callbacks */ + PyTypeObject *tp = Py_TYPE(dd); PyObject_GC_UnTrack(dd); Py_CLEAR(dd->default_factory); PyDict_Type.tp_dealloc((PyObject *)dd); + Py_DECREF(tp); } static PyObject * @@ -2117,11 +2112,24 @@ static PyObject* defdict_or(PyObject* left, PyObject* right) { PyObject *self, *other; - if (PyObject_TypeCheck(left, &defdict_type)) { + + // Find module state + PyTypeObject *tp = Py_TYPE(left); + PyObject *mod = PyType_GetModuleByDef(tp, &_collectionsmodule); + if (mod == NULL) { + PyErr_Clear(); + tp = Py_TYPE(right); + mod = PyType_GetModuleByDef(tp, &_collectionsmodule); + } + assert(mod != NULL); + collections_state *state = get_module_state(mod); + + if (PyObject_TypeCheck(left, state->defdict_type)) { self = left; other = right; } else { + assert(PyObject_TypeCheck(right, state->defdict_type)); self = right; other = left; } @@ -2141,13 +2149,10 @@ defdict_or(PyObject* left, PyObject* right) return new; } -static PyNumberMethods defdict_as_number = { - .nb_or = defdict_or, -}; - static int defdict_traverse(PyObject *self, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(self)); Py_VISIT(((defdictobject *)self)->default_factory); return PyDict_Type.tp_traverse(self, visit, arg); } @@ -2203,48 +2208,28 @@ passed to the dict constructor, including keyword arguments.\n\ /* See comment in xxsubtype.c */ #define DEFERRED_ADDRESS(ADDR) 0 -static PyTypeObject defdict_type = { - PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0) - "collections.defaultdict", /* tp_name */ - sizeof(defdictobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)defdict_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)defdict_repr, /* tp_repr */ - &defdict_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - /* tp_flags */ - defdict_doc, /* tp_doc */ - defdict_traverse, /* tp_traverse */ - (inquiry)defdict_tp_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset*/ - 0, /* tp_iter */ - 0, /* tp_iternext */ - defdict_methods, /* tp_methods */ - defdict_members, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&PyDict_Type), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - defdict_init, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - 0, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyType_Slot defdict_slots[] = { + {Py_tp_dealloc, defdict_dealloc}, + {Py_tp_repr, defdict_repr}, + {Py_nb_or, defdict_or}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)defdict_doc}, + {Py_tp_traverse, defdict_traverse}, + {Py_tp_clear, defdict_tp_clear}, + {Py_tp_methods, defdict_methods}, + {Py_tp_members, defdict_members}, + {Py_tp_init, defdict_init}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec defdict_spec = { + .name = "collections.defaultdict", + .basicsize = sizeof(defdictobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = defdict_slots, }; /* helper function for Counter *********************************************/ @@ -2442,6 +2427,7 @@ static int tuplegetter_traverse(PyObject *self, visitproc visit, void *arg) { _tuplegetterobject *tuplegetter = (_tuplegetterobject *)self; + Py_VISIT(Py_TYPE(tuplegetter)); Py_VISIT(tuplegetter->doc); return 0; } @@ -2457,9 +2443,11 @@ tuplegetter_clear(PyObject *self) static void tuplegetter_dealloc(_tuplegetterobject *self) { + PyTypeObject *tp = Py_TYPE(self); PyObject_GC_UnTrack(self); tuplegetter_clear((PyObject*)self); - Py_TYPE(self)->tp_free((PyObject*)self); + tp->tp_free((PyObject*)self); + Py_DECREF(tp); } static PyObject* @@ -2487,52 +2475,60 @@ static PyMethodDef tuplegetter_methods[] = { {NULL}, }; -static PyTypeObject tuplegetter_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_collections._tuplegetter", /* tp_name */ - sizeof(_tuplegetterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)tuplegetter_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)tuplegetter_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)tuplegetter_traverse, /* tp_traverse */ - (inquiry)tuplegetter_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - tuplegetter_methods, /* tp_methods */ - tuplegetter_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - tuplegetter_descr_get, /* tp_descr_get */ - tuplegetter_descr_set, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - tuplegetter_new, /* tp_new */ - 0, +static PyType_Slot tuplegetter_slots[] = { + {Py_tp_dealloc, tuplegetter_dealloc}, + {Py_tp_repr, tuplegetter_repr}, + {Py_tp_traverse, tuplegetter_traverse}, + {Py_tp_clear, tuplegetter_clear}, + {Py_tp_methods, tuplegetter_methods}, + {Py_tp_members, tuplegetter_members}, + {Py_tp_descr_get, tuplegetter_descr_get}, + {Py_tp_descr_set, tuplegetter_descr_set}, + {Py_tp_new, tuplegetter_new}, + {0, NULL}, +}; + +static PyType_Spec tuplegetter_spec = { + .name = "collections._tuplegetter", + .basicsize = sizeof(_tuplegetterobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = tuplegetter_slots, }; /* module level code ********************************************************/ +static int +collections_traverse(PyObject *mod, visitproc visit, void *arg) +{ + collections_state *state = get_module_state(mod); + Py_VISIT(state->deque_type); + Py_VISIT(state->defdict_type); + Py_VISIT(state->dequeiter_type); + Py_VISIT(state->dequereviter_type); + Py_VISIT(state->tuplegetter_type); + return 0; +} + +static int +collections_clear(PyObject *mod) +{ + collections_state *state = get_module_state(mod); + Py_CLEAR(state->deque_type); + Py_CLEAR(state->defdict_type); + Py_CLEAR(state->dequeiter_type); + Py_CLEAR(state->dequereviter_type); + Py_CLEAR(state->tuplegetter_type); + return 0; +} + +static void +collections_free(void *module) +{ + collections_clear((PyObject *)module); +} + PyDoc_STRVAR(collections_doc, "High performance data structures.\n\ - deque: ordered collection accessible from endpoints only\n\ @@ -2544,43 +2540,50 @@ static struct PyMethodDef collections_methods[] = { {NULL, NULL} /* sentinel */ }; +#define ADD_TYPE(MOD, SPEC, TYPE, BASE) do { \ + TYPE = (PyTypeObject *)PyType_FromMetaclass(NULL, MOD, SPEC, \ + (PyObject *)BASE); \ + if (TYPE == NULL) { \ + return -1; \ + } \ + if (PyModule_AddType(MOD, TYPE) < 0) { \ + return -1; \ + } \ +} while (0) + static int collections_exec(PyObject *module) { - PyTypeObject *typelist[] = { - &deque_type, - &defdict_type, - &PyODict_Type, - &dequeiter_type, - &dequereviter_type, - &tuplegetter_type - }; - - defdict_type.tp_base = &PyDict_Type; - - for (size_t i = 0; i < Py_ARRAY_LENGTH(typelist); i++) { - if (PyModule_AddType(module, typelist[i]) < 0) { - return -1; - } + collections_state *state = get_module_state(module); + ADD_TYPE(module, &deque_spec, state->deque_type, NULL); + ADD_TYPE(module, &defdict_spec, state->defdict_type, &PyDict_Type); + ADD_TYPE(module, &dequeiter_spec, state->dequeiter_type, NULL); + ADD_TYPE(module, &dequereviter_spec, state->dequereviter_type, NULL); + ADD_TYPE(module, &tuplegetter_spec, state->tuplegetter_type, NULL); + + if (PyModule_AddType(module, &PyODict_Type) < 0) { + return -1; } return 0; } +#undef ADD_TYPE + static struct PyModuleDef_Slot collections_slots[] = { {Py_mod_exec, collections_exec}, {0, NULL} }; static struct PyModuleDef _collectionsmodule = { - PyModuleDef_HEAD_INIT, - "_collections", - collections_doc, - 0, - collections_methods, - collections_slots, - NULL, - NULL, - NULL + .m_base = PyModuleDef_HEAD_INIT, + .m_name = "_collections", + .m_doc = collections_doc, + .m_size = sizeof(collections_state), + .m_methods = collections_methods, + .m_slots = collections_slots, + .m_traverse = collections_traverse, + .m_clear = collections_clear, + .m_free = collections_free, }; PyMODINIT_FUNC diff --git a/Modules/clinic/_collectionsmodule.c.h b/Modules/clinic/_collectionsmodule.c.h index 8ea0255b0610..3882d069216e 100644 --- a/Modules/clinic/_collectionsmodule.c.h +++ b/Modules/clinic/_collectionsmodule.c.h @@ -46,7 +46,7 @@ static PyObject * tuplegetter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; - PyTypeObject *base_tp = &tuplegetter_type; + PyTypeObject *base_tp = clinic_state()->tuplegetter_type; Py_ssize_t index; PyObject *doc; @@ -75,4 +75,4 @@ tuplegetter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=91a0f221c7b1f96c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=00e516317d2b8bed input=a9049054013a1b77]*/ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 823340ecc491..5c173b1041e3 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -316,11 +316,6 @@ Python/instrumentation.c - _PyInstrumentation_MISSING - ##----------------------- ## static types -Modules/_collectionsmodule.c - defdict_type - -Modules/_collectionsmodule.c - deque_type - -Modules/_collectionsmodule.c - dequeiter_type - -Modules/_collectionsmodule.c - dequereviter_type - -Modules/_collectionsmodule.c - tuplegetter_type - Modules/_io/bufferedio.c - PyBufferedIOBase_Type - Modules/_io/bytesio.c - _PyBytesIOBuffer_Type - Modules/_io/iobase.c - PyIOBase_Type - From webhook-mailer at python.org Wed Apr 12 14:27:27 2023 From: webhook-mailer at python.org (brettcannon) Date: Wed, 12 Apr 2023 18:27:27 -0000 Subject: [Python-checkins] gh-103326: Remove `Python/importlib.h` (GH-103331) Message-ID: https://github.com/python/cpython/commit/7f3c10650385907b5a2234edb2b1334cafd47a0a commit: 7f3c10650385907b5a2234edb2b1334cafd47a0a branch: main author: Nikita Sobolev committer: brettcannon date: 2023-04-12T11:27:14-07:00 summary: gh-103326: Remove `Python/importlib.h` (GH-103331) Co-authored-by: Brett Cannon Co-authored-by: Hugo van Kemenade files: D Python/importlib.h M .github/CODEOWNERS M Programs/_freeze_module.c M Tools/c-analyzer/cpython/_parser.py M configure M configure.ac diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 60af0519cdb7..9149b38d8760 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -61,11 +61,7 @@ Python/traceback.c @iritkatriel /Tools/build/parse_html5_entities.py @ezio-melotti # Import (including importlib). -# Ignoring importlib.h so as to not get flagged on -# all pull requests that change the emitted -# bytecode. -**/*import*.c @brettcannon @encukou @ericsnowcurrently @ncoghlan @warsaw -**/*import*.py @brettcannon @encukou @ericsnowcurrently @ncoghlan @warsaw +**/*import* @brettcannon @encukou @ericsnowcurrently @ncoghlan @warsaw **/*importlib/resources/* @jaraco @warsaw @FFY00 **/importlib/metadata/* @jaraco @warsaw diff --git a/Programs/_freeze_module.c b/Programs/_freeze_module.c index 90fc2dc6e87d..e55f1d56745c 100644 --- a/Programs/_freeze_module.c +++ b/Programs/_freeze_module.c @@ -1,6 +1,5 @@ /* This is built as a stand-alone executable by the Makefile, and helps turn - modules into frozen modules (like Lib/importlib/_bootstrap.py - into Python/importlib.h). + modules into frozen modules. This is used directly by Tools/build/freeze_modules.py, and indirectly by "make regen-frozen". diff --git a/Python/importlib.h b/Python/importlib.h deleted file mode 100644 index 586f3b21f462..000000000000 --- a/Python/importlib.h +++ /dev/null @@ -1,1783 +0,0 @@ -/* Auto-generated by Programs/_freeze_importlib.c */ -const unsigned char _Py_M__importlib_bootstrap[] = { - 99,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,4,0,0,0,64,0,0,0,115,194,1,0,0,100,0, - 90,0,100,1,97,1,100,2,100,3,132,0,90,2,100,4, - 100,5,132,0,90,3,105,0,90,4,105,0,90,5,71,0, - 100,6,100,7,132,0,100,7,101,6,131,3,90,7,71,0, - 100,8,100,9,132,0,100,9,131,2,90,8,71,0,100,10, - 100,11,132,0,100,11,131,2,90,9,71,0,100,12,100,13, - 132,0,100,13,131,2,90,10,100,14,100,15,132,0,90,11, - 100,16,100,17,132,0,90,12,100,18,100,19,132,0,90,13, - 100,20,100,21,156,1,100,22,100,23,132,2,90,14,100,24, - 100,25,132,0,90,15,100,26,100,27,132,0,90,16,100,28, - 100,29,132,0,90,17,100,30,100,31,132,0,90,18,71,0, - 100,32,100,33,132,0,100,33,131,2,90,19,100,1,100,1, - 100,34,156,2,100,35,100,36,132,2,90,20,100,94,100,37, - 100,38,132,1,90,21,100,39,100,40,156,1,100,41,100,42, - 132,2,90,22,100,43,100,44,132,0,90,23,100,45,100,46, - 132,0,90,24,100,47,100,48,132,0,90,25,100,49,100,50, - 132,0,90,26,100,51,100,52,132,0,90,27,100,53,100,54, - 132,0,90,28,71,0,100,55,100,56,132,0,100,56,131,2, - 90,29,71,0,100,57,100,58,132,0,100,58,131,2,90,30, - 71,0,100,59,100,60,132,0,100,60,131,2,90,31,100,61, - 100,62,132,0,90,32,100,63,100,64,132,0,90,33,100,95, - 100,65,100,66,132,1,90,34,100,67,100,68,132,0,90,35, - 100,69,90,36,101,36,100,70,23,0,90,37,100,71,100,72, - 132,0,90,38,101,39,131,0,90,40,100,73,100,74,132,0, - 90,41,100,96,100,76,100,77,132,1,90,42,100,39,100,78, - 156,1,100,79,100,80,132,2,90,43,100,81,100,82,132,0, - 90,44,100,97,100,84,100,85,132,1,90,45,100,86,100,87, - 132,0,90,46,100,88,100,89,132,0,90,47,100,90,100,91, - 132,0,90,48,100,92,100,93,132,0,90,49,100,1,83,0, - 41,98,97,83,1,0,0,67,111,114,101,32,105,109,112,108, - 101,109,101,110,116,97,116,105,111,110,32,111,102,32,105,109, - 112,111,114,116,46,10,10,84,104,105,115,32,109,111,100,117, - 108,101,32,105,115,32,78,79,84,32,109,101,97,110,116,32, - 116,111,32,98,101,32,100,105,114,101,99,116,108,121,32,105, - 109,112,111,114,116,101,100,33,32,73,116,32,104,97,115,32, - 98,101,101,110,32,100,101,115,105,103,110,101,100,32,115,117, - 99,104,10,116,104,97,116,32,105,116,32,99,97,110,32,98, - 101,32,98,111,111,116,115,116,114,97,112,112,101,100,32,105, - 110,116,111,32,80,121,116,104,111,110,32,97,115,32,116,104, - 101,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110, - 32,111,102,32,105,109,112,111,114,116,46,32,65,115,10,115, - 117,99,104,32,105,116,32,114,101,113,117,105,114,101,115,32, - 116,104,101,32,105,110,106,101,99,116,105,111,110,32,111,102, - 32,115,112,101,99,105,102,105,99,32,109,111,100,117,108,101, - 115,32,97,110,100,32,97,116,116,114,105,98,117,116,101,115, - 32,105,110,32,111,114,100,101,114,32,116,111,10,119,111,114, - 107,46,32,79,110,101,32,115,104,111,117,108,100,32,117,115, - 101,32,105,109,112,111,114,116,108,105,98,32,97,115,32,116, - 104,101,32,112,117,98,108,105,99,45,102,97,99,105,110,103, - 32,118,101,114,115,105,111,110,32,111,102,32,116,104,105,115, - 32,109,111,100,117,108,101,46,10,10,78,99,2,0,0,0, - 0,0,0,0,0,0,0,0,3,0,0,0,7,0,0,0, - 67,0,0,0,115,56,0,0,0,100,1,68,0,93,32,125, - 2,116,0,124,1,124,2,131,2,114,4,116,1,124,0,124, - 2,116,2,124,1,124,2,131,2,131,3,1,0,113,4,124, - 0,106,3,160,4,124,1,106,3,161,1,1,0,100,2,83, - 0,41,3,122,47,83,105,109,112,108,101,32,115,117,98,115, - 116,105,116,117,116,101,32,102,111,114,32,102,117,110,99,116, - 111,111,108,115,46,117,112,100,97,116,101,95,119,114,97,112, - 112,101,114,46,41,4,218,10,95,95,109,111,100,117,108,101, - 95,95,218,8,95,95,110,97,109,101,95,95,218,12,95,95, - 113,117,97,108,110,97,109,101,95,95,218,7,95,95,100,111, - 99,95,95,78,41,5,218,7,104,97,115,97,116,116,114,218, - 7,115,101,116,97,116,116,114,218,7,103,101,116,97,116,116, - 114,218,8,95,95,100,105,99,116,95,95,218,6,117,112,100, - 97,116,101,41,3,90,3,110,101,119,90,3,111,108,100,218, - 7,114,101,112,108,97,99,101,169,0,114,10,0,0,0,250, - 29,60,102,114,111,122,101,110,32,105,109,112,111,114,116,108, - 105,98,46,95,98,111,111,116,115,116,114,97,112,62,218,5, - 95,119,114,97,112,27,0,0,0,115,8,0,0,0,0,2, - 8,1,10,1,20,1,114,12,0,0,0,99,1,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0, - 67,0,0,0,115,12,0,0,0,116,0,116,1,131,1,124, - 0,131,1,83,0,169,1,78,41,2,218,4,116,121,112,101, - 218,3,115,121,115,169,1,218,4,110,97,109,101,114,10,0, - 0,0,114,10,0,0,0,114,11,0,0,0,218,11,95,110, - 101,119,95,109,111,100,117,108,101,35,0,0,0,115,2,0, - 0,0,0,1,114,18,0,0,0,99,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,1,0,0,0,64,0, - 0,0,115,12,0,0,0,101,0,90,1,100,0,90,2,100, - 1,83,0,41,2,218,14,95,68,101,97,100,108,111,99,107, - 69,114,114,111,114,78,41,3,114,1,0,0,0,114,0,0, - 0,0,114,2,0,0,0,114,10,0,0,0,114,10,0,0, - 0,114,10,0,0,0,114,11,0,0,0,114,19,0,0,0, - 48,0,0,0,115,2,0,0,0,8,1,114,19,0,0,0, - 99,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,2,0,0,0,64,0,0,0,115,56,0,0,0,101,0, - 90,1,100,0,90,2,100,1,90,3,100,2,100,3,132,0, - 90,4,100,4,100,5,132,0,90,5,100,6,100,7,132,0, - 90,6,100,8,100,9,132,0,90,7,100,10,100,11,132,0, - 90,8,100,12,83,0,41,13,218,11,95,77,111,100,117,108, - 101,76,111,99,107,122,169,65,32,114,101,99,117,114,115,105, - 118,101,32,108,111,99,107,32,105,109,112,108,101,109,101,110, - 116,97,116,105,111,110,32,119,104,105,99,104,32,105,115,32, - 97,98,108,101,32,116,111,32,100,101,116,101,99,116,32,100, - 101,97,100,108,111,99,107,115,10,32,32,32,32,40,101,46, - 103,46,32,116,104,114,101,97,100,32,49,32,116,114,121,105, - 110,103,32,116,111,32,116,97,107,101,32,108,111,99,107,115, - 32,65,32,116,104,101,110,32,66,44,32,97,110,100,32,116, - 104,114,101,97,100,32,50,32,116,114,121,105,110,103,32,116, - 111,10,32,32,32,32,116,97,107,101,32,108,111,99,107,115, - 32,66,32,116,104,101,110,32,65,41,46,10,32,32,32,32, - 99,2,0,0,0,0,0,0,0,0,0,0,0,2,0,0, - 0,2,0,0,0,67,0,0,0,115,48,0,0,0,116,0, - 160,1,161,0,124,0,95,2,116,0,160,1,161,0,124,0, - 95,3,124,1,124,0,95,4,100,0,124,0,95,5,100,1, - 124,0,95,6,100,1,124,0,95,7,100,0,83,0,169,2, - 78,233,0,0,0,0,41,8,218,7,95,116,104,114,101,97, - 100,90,13,97,108,108,111,99,97,116,101,95,108,111,99,107, - 218,4,108,111,99,107,218,6,119,97,107,101,117,112,114,17, - 0,0,0,218,5,111,119,110,101,114,218,5,99,111,117,110, - 116,218,7,119,97,105,116,101,114,115,169,2,218,4,115,101, - 108,102,114,17,0,0,0,114,10,0,0,0,114,10,0,0, - 0,114,11,0,0,0,218,8,95,95,105,110,105,116,95,95, - 58,0,0,0,115,12,0,0,0,0,1,10,1,10,1,6, - 1,6,1,6,1,122,20,95,77,111,100,117,108,101,76,111, - 99,107,46,95,95,105,110,105,116,95,95,99,1,0,0,0, - 0,0,0,0,0,0,0,0,4,0,0,0,3,0,0,0, - 67,0,0,0,115,60,0,0,0,116,0,160,1,161,0,125, - 1,124,0,106,2,125,2,116,3,160,4,124,2,161,1,125, - 3,124,3,100,0,107,8,114,36,100,1,83,0,124,3,106, - 2,125,2,124,2,124,1,107,2,114,14,100,2,83,0,113, - 14,100,0,83,0,41,3,78,70,84,41,5,114,23,0,0, - 0,218,9,103,101,116,95,105,100,101,110,116,114,26,0,0, - 0,218,12,95,98,108,111,99,107,105,110,103,95,111,110,218, - 3,103,101,116,41,4,114,30,0,0,0,90,2,109,101,218, - 3,116,105,100,114,24,0,0,0,114,10,0,0,0,114,10, - 0,0,0,114,11,0,0,0,218,12,104,97,115,95,100,101, - 97,100,108,111,99,107,66,0,0,0,115,16,0,0,0,0, - 2,8,1,6,2,10,1,8,1,4,1,6,1,8,1,122, - 24,95,77,111,100,117,108,101,76,111,99,107,46,104,97,115, - 95,100,101,97,100,108,111,99,107,99,1,0,0,0,0,0, - 0,0,0,0,0,0,2,0,0,0,9,0,0,0,67,0, - 0,0,115,178,0,0,0,116,0,160,1,161,0,125,1,124, - 0,116,2,124,1,60,0,122,148,124,0,106,3,143,110,1, - 0,124,0,106,4,100,1,107,2,115,46,124,0,106,5,124, - 1,107,2,114,84,124,1,124,0,95,5,124,0,4,0,106, - 4,100,2,55,0,2,0,95,4,87,0,53,0,81,0,82, - 0,163,0,87,0,162,86,100,3,83,0,124,0,160,6,161, - 0,114,104,116,7,100,4,124,0,22,0,131,1,130,1,124, - 0,106,8,160,9,100,5,161,1,114,130,124,0,4,0,106, - 10,100,2,55,0,2,0,95,10,87,0,53,0,81,0,82, - 0,88,0,124,0,106,8,160,9,161,0,1,0,124,0,106, - 8,160,11,161,0,1,0,113,18,87,0,53,0,116,2,124, - 1,61,0,88,0,100,6,83,0,41,7,122,185,10,32,32, - 32,32,32,32,32,32,65,99,113,117,105,114,101,32,116,104, - 101,32,109,111,100,117,108,101,32,108,111,99,107,46,32,32, - 73,102,32,97,32,112,111,116,101,110,116,105,97,108,32,100, - 101,97,100,108,111,99,107,32,105,115,32,100,101,116,101,99, - 116,101,100,44,10,32,32,32,32,32,32,32,32,97,32,95, - 68,101,97,100,108,111,99,107,69,114,114,111,114,32,105,115, - 32,114,97,105,115,101,100,46,10,32,32,32,32,32,32,32, - 32,79,116,104,101,114,119,105,115,101,44,32,116,104,101,32, - 108,111,99,107,32,105,115,32,97,108,119,97,121,115,32,97, - 99,113,117,105,114,101,100,32,97,110,100,32,84,114,117,101, - 32,105,115,32,114,101,116,117,114,110,101,100,46,10,32,32, - 32,32,32,32,32,32,114,22,0,0,0,233,1,0,0,0, - 84,122,23,100,101,97,100,108,111,99,107,32,100,101,116,101, - 99,116,101,100,32,98,121,32,37,114,70,78,41,12,114,23, - 0,0,0,114,32,0,0,0,114,33,0,0,0,114,24,0, - 0,0,114,27,0,0,0,114,26,0,0,0,114,36,0,0, - 0,114,19,0,0,0,114,25,0,0,0,218,7,97,99,113, - 117,105,114,101,114,28,0,0,0,218,7,114,101,108,101,97, - 115,101,169,2,114,30,0,0,0,114,35,0,0,0,114,10, - 0,0,0,114,10,0,0,0,114,11,0,0,0,114,38,0, - 0,0,78,0,0,0,115,30,0,0,0,0,6,8,1,8, - 1,2,2,8,1,20,1,6,1,14,1,18,1,8,1,12, - 1,12,1,24,2,10,1,16,2,122,19,95,77,111,100,117, - 108,101,76,111,99,107,46,97,99,113,117,105,114,101,99,1, - 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,9, - 0,0,0,67,0,0,0,115,122,0,0,0,116,0,160,1, - 161,0,125,1,124,0,106,2,143,98,1,0,124,0,106,3, - 124,1,107,3,114,34,116,4,100,1,131,1,130,1,124,0, - 106,5,100,2,107,4,115,48,74,0,130,1,124,0,4,0, - 106,5,100,3,56,0,2,0,95,5,124,0,106,5,100,2, - 107,2,114,108,100,0,124,0,95,3,124,0,106,6,114,108, - 124,0,4,0,106,6,100,3,56,0,2,0,95,6,124,0, - 106,7,160,8,161,0,1,0,87,0,53,0,81,0,82,0, - 88,0,100,0,83,0,41,4,78,250,31,99,97,110,110,111, - 116,32,114,101,108,101,97,115,101,32,117,110,45,97,99,113, - 117,105,114,101,100,32,108,111,99,107,114,22,0,0,0,114, - 37,0,0,0,41,9,114,23,0,0,0,114,32,0,0,0, - 114,24,0,0,0,114,26,0,0,0,218,12,82,117,110,116, - 105,109,101,69,114,114,111,114,114,27,0,0,0,114,28,0, - 0,0,114,25,0,0,0,114,39,0,0,0,114,40,0,0, - 0,114,10,0,0,0,114,10,0,0,0,114,11,0,0,0, - 114,39,0,0,0,103,0,0,0,115,22,0,0,0,0,1, - 8,1,8,1,10,1,8,1,14,1,14,1,10,1,6,1, - 6,1,14,1,122,19,95,77,111,100,117,108,101,76,111,99, - 107,46,114,101,108,101,97,115,101,99,1,0,0,0,0,0, - 0,0,0,0,0,0,1,0,0,0,5,0,0,0,67,0, - 0,0,115,22,0,0,0,100,1,124,0,106,0,155,2,100, - 2,116,1,124,0,131,1,155,0,157,4,83,0,41,3,78, - 122,12,95,77,111,100,117,108,101,76,111,99,107,40,250,5, - 41,32,97,116,32,169,2,114,17,0,0,0,218,2,105,100, - 169,1,114,30,0,0,0,114,10,0,0,0,114,10,0,0, - 0,114,11,0,0,0,218,8,95,95,114,101,112,114,95,95, - 116,0,0,0,115,2,0,0,0,0,1,122,20,95,77,111, - 100,117,108,101,76,111,99,107,46,95,95,114,101,112,114,95, - 95,78,41,9,114,1,0,0,0,114,0,0,0,0,114,2, - 0,0,0,114,3,0,0,0,114,31,0,0,0,114,36,0, - 0,0,114,38,0,0,0,114,39,0,0,0,114,47,0,0, - 0,114,10,0,0,0,114,10,0,0,0,114,10,0,0,0, - 114,11,0,0,0,114,20,0,0,0,52,0,0,0,115,12, - 0,0,0,8,1,4,5,8,8,8,12,8,25,8,13,114, - 20,0,0,0,99,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,2,0,0,0,64,0,0,0,115,48,0, - 0,0,101,0,90,1,100,0,90,2,100,1,90,3,100,2, - 100,3,132,0,90,4,100,4,100,5,132,0,90,5,100,6, - 100,7,132,0,90,6,100,8,100,9,132,0,90,7,100,10, - 83,0,41,11,218,16,95,68,117,109,109,121,77,111,100,117, - 108,101,76,111,99,107,122,86,65,32,115,105,109,112,108,101, - 32,95,77,111,100,117,108,101,76,111,99,107,32,101,113,117, - 105,118,97,108,101,110,116,32,102,111,114,32,80,121,116,104, - 111,110,32,98,117,105,108,100,115,32,119,105,116,104,111,117, - 116,10,32,32,32,32,109,117,108,116,105,45,116,104,114,101, - 97,100,105,110,103,32,115,117,112,112,111,114,116,46,99,2, - 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2, - 0,0,0,67,0,0,0,115,16,0,0,0,124,1,124,0, - 95,0,100,1,124,0,95,1,100,0,83,0,114,21,0,0, - 0,41,2,114,17,0,0,0,114,27,0,0,0,114,29,0, - 0,0,114,10,0,0,0,114,10,0,0,0,114,11,0,0, - 0,114,31,0,0,0,124,0,0,0,115,4,0,0,0,0, - 1,6,1,122,25,95,68,117,109,109,121,77,111,100,117,108, - 101,76,111,99,107,46,95,95,105,110,105,116,95,95,99,1, - 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,3, - 0,0,0,67,0,0,0,115,18,0,0,0,124,0,4,0, - 106,0,100,1,55,0,2,0,95,0,100,2,83,0,41,3, - 78,114,37,0,0,0,84,41,1,114,27,0,0,0,114,46, - 0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,0, - 0,0,114,38,0,0,0,128,0,0,0,115,4,0,0,0, - 0,1,14,1,122,24,95,68,117,109,109,121,77,111,100,117, - 108,101,76,111,99,107,46,97,99,113,117,105,114,101,99,1, - 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,3, - 0,0,0,67,0,0,0,115,36,0,0,0,124,0,106,0, - 100,1,107,2,114,18,116,1,100,2,131,1,130,1,124,0, - 4,0,106,0,100,3,56,0,2,0,95,0,100,0,83,0, - 41,4,78,114,22,0,0,0,114,41,0,0,0,114,37,0, - 0,0,41,2,114,27,0,0,0,114,42,0,0,0,114,46, - 0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,0, - 0,0,114,39,0,0,0,132,0,0,0,115,6,0,0,0, - 0,1,10,1,8,1,122,24,95,68,117,109,109,121,77,111, - 100,117,108,101,76,111,99,107,46,114,101,108,101,97,115,101, - 99,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0, - 0,5,0,0,0,67,0,0,0,115,22,0,0,0,100,1, - 124,0,106,0,155,2,100,2,116,1,124,0,131,1,155,0, - 157,4,83,0,41,3,78,122,17,95,68,117,109,109,121,77, - 111,100,117,108,101,76,111,99,107,40,114,43,0,0,0,114, - 44,0,0,0,114,46,0,0,0,114,10,0,0,0,114,10, - 0,0,0,114,11,0,0,0,114,47,0,0,0,137,0,0, - 0,115,2,0,0,0,0,1,122,25,95,68,117,109,109,121, - 77,111,100,117,108,101,76,111,99,107,46,95,95,114,101,112, - 114,95,95,78,41,8,114,1,0,0,0,114,0,0,0,0, - 114,2,0,0,0,114,3,0,0,0,114,31,0,0,0,114, - 38,0,0,0,114,39,0,0,0,114,47,0,0,0,114,10, - 0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,0, - 0,0,114,48,0,0,0,120,0,0,0,115,10,0,0,0, - 8,1,4,3,8,4,8,4,8,5,114,48,0,0,0,99, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 2,0,0,0,64,0,0,0,115,36,0,0,0,101,0,90, - 1,100,0,90,2,100,1,100,2,132,0,90,3,100,3,100, - 4,132,0,90,4,100,5,100,6,132,0,90,5,100,7,83, - 0,41,8,218,18,95,77,111,100,117,108,101,76,111,99,107, - 77,97,110,97,103,101,114,99,2,0,0,0,0,0,0,0, - 0,0,0,0,2,0,0,0,2,0,0,0,67,0,0,0, - 115,16,0,0,0,124,1,124,0,95,0,100,0,124,0,95, - 1,100,0,83,0,114,13,0,0,0,41,2,218,5,95,110, - 97,109,101,218,5,95,108,111,99,107,114,29,0,0,0,114, - 10,0,0,0,114,10,0,0,0,114,11,0,0,0,114,31, - 0,0,0,143,0,0,0,115,4,0,0,0,0,1,6,1, - 122,27,95,77,111,100,117,108,101,76,111,99,107,77,97,110, - 97,103,101,114,46,95,95,105,110,105,116,95,95,99,1,0, - 0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0, - 0,0,67,0,0,0,115,26,0,0,0,116,0,124,0,106, - 1,131,1,124,0,95,2,124,0,106,2,160,3,161,0,1, - 0,100,0,83,0,114,13,0,0,0,41,4,218,16,95,103, - 101,116,95,109,111,100,117,108,101,95,108,111,99,107,114,50, - 0,0,0,114,51,0,0,0,114,38,0,0,0,114,46,0, - 0,0,114,10,0,0,0,114,10,0,0,0,114,11,0,0, - 0,218,9,95,95,101,110,116,101,114,95,95,147,0,0,0, - 115,4,0,0,0,0,1,12,1,122,28,95,77,111,100,117, - 108,101,76,111,99,107,77,97,110,97,103,101,114,46,95,95, - 101,110,116,101,114,95,95,99,1,0,0,0,0,0,0,0, - 0,0,0,0,3,0,0,0,2,0,0,0,79,0,0,0, - 115,14,0,0,0,124,0,106,0,160,1,161,0,1,0,100, - 0,83,0,114,13,0,0,0,41,2,114,51,0,0,0,114, - 39,0,0,0,41,3,114,30,0,0,0,218,4,97,114,103, - 115,90,6,107,119,97,114,103,115,114,10,0,0,0,114,10, - 0,0,0,114,11,0,0,0,218,8,95,95,101,120,105,116, - 95,95,151,0,0,0,115,2,0,0,0,0,1,122,27,95, - 77,111,100,117,108,101,76,111,99,107,77,97,110,97,103,101, - 114,46,95,95,101,120,105,116,95,95,78,41,6,114,1,0, - 0,0,114,0,0,0,0,114,2,0,0,0,114,31,0,0, - 0,114,53,0,0,0,114,55,0,0,0,114,10,0,0,0, - 114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,114, - 49,0,0,0,141,0,0,0,115,6,0,0,0,8,2,8, - 4,8,4,114,49,0,0,0,99,1,0,0,0,0,0,0, - 0,0,0,0,0,3,0,0,0,8,0,0,0,67,0,0, - 0,115,130,0,0,0,116,0,160,1,161,0,1,0,122,106, - 122,14,116,3,124,0,25,0,131,0,125,1,87,0,110,24, - 4,0,116,4,107,10,114,48,1,0,1,0,1,0,100,1, - 125,1,89,0,110,2,88,0,124,1,100,1,107,8,114,112, - 116,5,100,1,107,8,114,76,116,6,124,0,131,1,125,1, - 110,8,116,7,124,0,131,1,125,1,124,0,102,1,100,2, - 100,3,132,1,125,2,116,8,160,9,124,1,124,2,161,2, - 116,3,124,0,60,0,87,0,53,0,116,0,160,2,161,0, - 1,0,88,0,124,1,83,0,41,4,122,139,71,101,116,32, - 111,114,32,99,114,101,97,116,101,32,116,104,101,32,109,111, - 100,117,108,101,32,108,111,99,107,32,102,111,114,32,97,32, - 103,105,118,101,110,32,109,111,100,117,108,101,32,110,97,109, - 101,46,10,10,32,32,32,32,65,99,113,117,105,114,101,47, - 114,101,108,101,97,115,101,32,105,110,116,101,114,110,97,108, - 108,121,32,116,104,101,32,103,108,111,98,97,108,32,105,109, - 112,111,114,116,32,108,111,99,107,32,116,111,32,112,114,111, - 116,101,99,116,10,32,32,32,32,95,109,111,100,117,108,101, - 95,108,111,99,107,115,46,78,99,2,0,0,0,0,0,0, - 0,0,0,0,0,2,0,0,0,8,0,0,0,83,0,0, - 0,115,48,0,0,0,116,0,160,1,161,0,1,0,122,24, - 116,3,160,4,124,1,161,1,124,0,107,8,114,30,116,3, - 124,1,61,0,87,0,53,0,116,0,160,2,161,0,1,0, - 88,0,100,0,83,0,114,13,0,0,0,41,5,218,4,95, - 105,109,112,218,12,97,99,113,117,105,114,101,95,108,111,99, - 107,218,12,114,101,108,101,97,115,101,95,108,111,99,107,218, - 13,95,109,111,100,117,108,101,95,108,111,99,107,115,114,34, - 0,0,0,41,2,218,3,114,101,102,114,17,0,0,0,114, - 10,0,0,0,114,10,0,0,0,114,11,0,0,0,218,2, - 99,98,176,0,0,0,115,10,0,0,0,0,1,8,1,2, - 4,14,1,10,2,122,28,95,103,101,116,95,109,111,100,117, - 108,101,95,108,111,99,107,46,60,108,111,99,97,108,115,62, - 46,99,98,41,10,114,56,0,0,0,114,57,0,0,0,114, - 58,0,0,0,114,59,0,0,0,218,8,75,101,121,69,114, - 114,111,114,114,23,0,0,0,114,48,0,0,0,114,20,0, - 0,0,218,8,95,119,101,97,107,114,101,102,114,60,0,0, - 0,41,3,114,17,0,0,0,114,24,0,0,0,114,61,0, - 0,0,114,10,0,0,0,114,10,0,0,0,114,11,0,0, - 0,114,52,0,0,0,157,0,0,0,115,28,0,0,0,0, - 6,8,1,2,1,2,1,14,1,14,1,10,2,8,1,8, - 1,10,2,8,2,12,11,20,2,10,2,114,52,0,0,0, - 99,1,0,0,0,0,0,0,0,0,0,0,0,2,0,0, - 0,8,0,0,0,67,0,0,0,115,54,0,0,0,116,0, - 124,0,131,1,125,1,122,12,124,1,160,1,161,0,1,0, - 87,0,110,20,4,0,116,2,107,10,114,40,1,0,1,0, - 1,0,89,0,110,10,88,0,124,1,160,3,161,0,1,0, - 100,1,83,0,41,2,122,189,65,99,113,117,105,114,101,115, - 32,116,104,101,110,32,114,101,108,101,97,115,101,115,32,116, - 104,101,32,109,111,100,117,108,101,32,108,111,99,107,32,102, - 111,114,32,97,32,103,105,118,101,110,32,109,111,100,117,108, - 101,32,110,97,109,101,46,10,10,32,32,32,32,84,104,105, - 115,32,105,115,32,117,115,101,100,32,116,111,32,101,110,115, - 117,114,101,32,97,32,109,111,100,117,108,101,32,105,115,32, - 99,111,109,112,108,101,116,101,108,121,32,105,110,105,116,105, - 97,108,105,122,101,100,44,32,105,110,32,116,104,101,10,32, - 32,32,32,101,118,101,110,116,32,105,116,32,105,115,32,98, - 101,105,110,103,32,105,109,112,111,114,116,101,100,32,98,121, - 32,97,110,111,116,104,101,114,32,116,104,114,101,97,100,46, - 10,32,32,32,32,78,41,4,114,52,0,0,0,114,38,0, - 0,0,114,19,0,0,0,114,39,0,0,0,41,2,114,17, - 0,0,0,114,24,0,0,0,114,10,0,0,0,114,10,0, - 0,0,114,11,0,0,0,218,19,95,108,111,99,107,95,117, - 110,108,111,99,107,95,109,111,100,117,108,101,194,0,0,0, - 115,12,0,0,0,0,6,8,1,2,1,12,1,14,3,6, - 2,114,64,0,0,0,99,1,0,0,0,0,0,0,0,0, - 0,0,0,3,0,0,0,3,0,0,0,79,0,0,0,115, - 10,0,0,0,124,0,124,1,124,2,142,1,83,0,41,1, - 97,46,1,0,0,114,101,109,111,118,101,95,105,109,112,111, - 114,116,108,105,98,95,102,114,97,109,101,115,32,105,110,32, - 105,109,112,111,114,116,46,99,32,119,105,108,108,32,97,108, - 119,97,121,115,32,114,101,109,111,118,101,32,115,101,113,117, - 101,110,99,101,115,10,32,32,32,32,111,102,32,105,109,112, - 111,114,116,108,105,98,32,102,114,97,109,101,115,32,116,104, - 97,116,32,101,110,100,32,119,105,116,104,32,97,32,99,97, - 108,108,32,116,111,32,116,104,105,115,32,102,117,110,99,116, - 105,111,110,10,10,32,32,32,32,85,115,101,32,105,116,32, - 105,110,115,116,101,97,100,32,111,102,32,97,32,110,111,114, - 109,97,108,32,99,97,108,108,32,105,110,32,112,108,97,99, - 101,115,32,119,104,101,114,101,32,105,110,99,108,117,100,105, - 110,103,32,116,104,101,32,105,109,112,111,114,116,108,105,98, - 10,32,32,32,32,102,114,97,109,101,115,32,105,110,116,114, - 111,100,117,99,101,115,32,117,110,119,97,110,116,101,100,32, - 110,111,105,115,101,32,105,110,116,111,32,116,104,101,32,116, - 114,97,99,101,98,97,99,107,32,40,101,46,103,46,32,119, - 104,101,110,32,101,120,101,99,117,116,105,110,103,10,32,32, - 32,32,109,111,100,117,108,101,32,99,111,100,101,41,10,32, - 32,32,32,114,10,0,0,0,41,3,218,1,102,114,54,0, - 0,0,90,4,107,119,100,115,114,10,0,0,0,114,10,0, - 0,0,114,11,0,0,0,218,25,95,99,97,108,108,95,119, - 105,116,104,95,102,114,97,109,101,115,95,114,101,109,111,118, - 101,100,211,0,0,0,115,2,0,0,0,0,8,114,66,0, - 0,0,114,37,0,0,0,41,1,218,9,118,101,114,98,111, - 115,105,116,121,99,1,0,0,0,0,0,0,0,1,0,0, - 0,3,0,0,0,4,0,0,0,71,0,0,0,115,54,0, - 0,0,116,0,106,1,106,2,124,1,107,5,114,50,124,0, - 160,3,100,1,161,1,115,30,100,2,124,0,23,0,125,0, - 116,4,124,0,106,5,124,2,142,0,116,0,106,6,100,3, - 141,2,1,0,100,4,83,0,41,5,122,61,80,114,105,110, - 116,32,116,104,101,32,109,101,115,115,97,103,101,32,116,111, - 32,115,116,100,101,114,114,32,105,102,32,45,118,47,80,89, - 84,72,79,78,86,69,82,66,79,83,69,32,105,115,32,116, - 117,114,110,101,100,32,111,110,46,41,2,250,1,35,122,7, - 105,109,112,111,114,116,32,122,2,35,32,41,1,90,4,102, - 105,108,101,78,41,7,114,15,0,0,0,218,5,102,108,97, - 103,115,218,7,118,101,114,98,111,115,101,218,10,115,116,97, - 114,116,115,119,105,116,104,218,5,112,114,105,110,116,218,6, - 102,111,114,109,97,116,218,6,115,116,100,101,114,114,41,3, - 218,7,109,101,115,115,97,103,101,114,67,0,0,0,114,54, - 0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,0, - 0,0,218,16,95,118,101,114,98,111,115,101,95,109,101,115, - 115,97,103,101,222,0,0,0,115,8,0,0,0,0,2,12, - 1,10,1,8,1,114,76,0,0,0,99,1,0,0,0,0, - 0,0,0,0,0,0,0,2,0,0,0,3,0,0,0,3, - 0,0,0,115,26,0,0,0,135,0,102,1,100,1,100,2, - 132,8,125,1,116,0,124,1,136,0,131,2,1,0,124,1, - 83,0,41,3,122,49,68,101,99,111,114,97,116,111,114,32, - 116,111,32,118,101,114,105,102,121,32,116,104,101,32,110,97, - 109,101,100,32,109,111,100,117,108,101,32,105,115,32,98,117, - 105,108,116,45,105,110,46,99,2,0,0,0,0,0,0,0, - 0,0,0,0,2,0,0,0,4,0,0,0,19,0,0,0, - 115,38,0,0,0,124,1,116,0,106,1,107,7,114,28,116, - 2,124,1,155,2,100,1,157,2,124,1,100,2,141,2,130, - 1,136,0,124,0,124,1,131,2,83,0,41,3,78,250,25, - 32,105,115,32,110,111,116,32,97,32,98,117,105,108,116,45, - 105,110,32,109,111,100,117,108,101,114,16,0,0,0,41,3, - 114,15,0,0,0,218,20,98,117,105,108,116,105,110,95,109, - 111,100,117,108,101,95,110,97,109,101,115,218,11,73,109,112, - 111,114,116,69,114,114,111,114,169,2,114,30,0,0,0,218, - 8,102,117,108,108,110,97,109,101,169,1,218,3,102,120,110, - 114,10,0,0,0,114,11,0,0,0,218,25,95,114,101,113, - 117,105,114,101,115,95,98,117,105,108,116,105,110,95,119,114, - 97,112,112,101,114,232,0,0,0,115,10,0,0,0,0,1, - 10,1,10,1,2,255,6,2,122,52,95,114,101,113,117,105, - 114,101,115,95,98,117,105,108,116,105,110,46,60,108,111,99, - 97,108,115,62,46,95,114,101,113,117,105,114,101,115,95,98, - 117,105,108,116,105,110,95,119,114,97,112,112,101,114,169,1, - 114,12,0,0,0,41,2,114,83,0,0,0,114,84,0,0, - 0,114,10,0,0,0,114,82,0,0,0,114,11,0,0,0, - 218,17,95,114,101,113,117,105,114,101,115,95,98,117,105,108, - 116,105,110,230,0,0,0,115,6,0,0,0,0,2,12,5, - 10,1,114,86,0,0,0,99,1,0,0,0,0,0,0,0, - 0,0,0,0,2,0,0,0,3,0,0,0,3,0,0,0, - 115,26,0,0,0,135,0,102,1,100,1,100,2,132,8,125, - 1,116,0,124,1,136,0,131,2,1,0,124,1,83,0,41, - 3,122,47,68,101,99,111,114,97,116,111,114,32,116,111,32, - 118,101,114,105,102,121,32,116,104,101,32,110,97,109,101,100, - 32,109,111,100,117,108,101,32,105,115,32,102,114,111,122,101, - 110,46,99,2,0,0,0,0,0,0,0,0,0,0,0,2, - 0,0,0,4,0,0,0,19,0,0,0,115,38,0,0,0, - 116,0,160,1,124,1,161,1,115,28,116,2,124,1,155,2, - 100,1,157,2,124,1,100,2,141,2,130,1,136,0,124,0, - 124,1,131,2,83,0,169,3,78,122,23,32,105,115,32,110, - 111,116,32,97,32,102,114,111,122,101,110,32,109,111,100,117, - 108,101,114,16,0,0,0,41,3,114,56,0,0,0,218,9, - 105,115,95,102,114,111,122,101,110,114,79,0,0,0,114,80, - 0,0,0,114,82,0,0,0,114,10,0,0,0,114,11,0, - 0,0,218,24,95,114,101,113,117,105,114,101,115,95,102,114, - 111,122,101,110,95,119,114,97,112,112,101,114,243,0,0,0, - 115,10,0,0,0,0,1,10,1,10,1,2,255,6,2,122, - 50,95,114,101,113,117,105,114,101,115,95,102,114,111,122,101, - 110,46,60,108,111,99,97,108,115,62,46,95,114,101,113,117, - 105,114,101,115,95,102,114,111,122,101,110,95,119,114,97,112, - 112,101,114,114,85,0,0,0,41,2,114,83,0,0,0,114, - 89,0,0,0,114,10,0,0,0,114,82,0,0,0,114,11, - 0,0,0,218,16,95,114,101,113,117,105,114,101,115,95,102, - 114,111,122,101,110,241,0,0,0,115,6,0,0,0,0,2, - 12,5,10,1,114,90,0,0,0,99,2,0,0,0,0,0, - 0,0,0,0,0,0,4,0,0,0,3,0,0,0,67,0, - 0,0,115,62,0,0,0,116,0,124,1,124,0,131,2,125, - 2,124,1,116,1,106,2,107,6,114,50,116,1,106,2,124, - 1,25,0,125,3,116,3,124,2,124,3,131,2,1,0,116, - 1,106,2,124,1,25,0,83,0,116,4,124,2,131,1,83, - 0,100,1,83,0,41,2,122,128,76,111,97,100,32,116,104, - 101,32,115,112,101,99,105,102,105,101,100,32,109,111,100,117, - 108,101,32,105,110,116,111,32,115,121,115,46,109,111,100,117, - 108,101,115,32,97,110,100,32,114,101,116,117,114,110,32,105, - 116,46,10,10,32,32,32,32,84,104,105,115,32,109,101,116, - 104,111,100,32,105,115,32,100,101,112,114,101,99,97,116,101, - 100,46,32,32,85,115,101,32,108,111,97,100,101,114,46,101, - 120,101,99,95,109,111,100,117,108,101,32,105,110,115,116,101, - 97,100,46,10,10,32,32,32,32,78,41,5,218,16,115,112, - 101,99,95,102,114,111,109,95,108,111,97,100,101,114,114,15, - 0,0,0,218,7,109,111,100,117,108,101,115,218,5,95,101, - 120,101,99,218,5,95,108,111,97,100,41,4,114,30,0,0, - 0,114,81,0,0,0,218,4,115,112,101,99,218,6,109,111, - 100,117,108,101,114,10,0,0,0,114,10,0,0,0,114,11, - 0,0,0,218,17,95,108,111,97,100,95,109,111,100,117,108, - 101,95,115,104,105,109,253,0,0,0,115,12,0,0,0,0, - 6,10,1,10,1,10,1,10,1,10,2,114,97,0,0,0, - 99,1,0,0,0,0,0,0,0,0,0,0,0,5,0,0, - 0,8,0,0,0,67,0,0,0,115,240,0,0,0,116,0, - 124,0,100,1,100,0,131,3,125,1,116,1,124,1,100,2, - 131,2,114,56,122,12,124,1,160,2,124,0,161,1,87,0, - 83,0,4,0,116,3,107,10,114,54,1,0,1,0,1,0, - 89,0,110,2,88,0,122,10,124,0,106,4,125,2,87,0, - 110,20,4,0,116,5,107,10,114,86,1,0,1,0,1,0, - 89,0,110,18,88,0,124,2,100,0,107,9,114,104,116,6, - 124,2,131,1,83,0,122,10,124,0,106,7,125,3,87,0, - 110,24,4,0,116,5,107,10,114,138,1,0,1,0,1,0, - 100,3,125,3,89,0,110,2,88,0,122,10,124,0,106,8, - 125,4,87,0,110,66,4,0,116,5,107,10,114,216,1,0, - 1,0,1,0,124,1,100,0,107,8,114,190,100,4,124,3, - 155,2,100,5,157,3,6,0,89,0,83,0,100,4,124,3, - 155,2,100,6,124,1,155,2,100,7,157,5,6,0,89,0, - 83,0,89,0,110,20,88,0,100,4,124,3,155,2,100,8, - 124,4,155,2,100,5,157,5,83,0,100,0,83,0,41,9, - 78,218,10,95,95,108,111,97,100,101,114,95,95,218,11,109, - 111,100,117,108,101,95,114,101,112,114,250,1,63,250,8,60, - 109,111,100,117,108,101,32,250,1,62,250,2,32,40,250,2, - 41,62,250,6,32,102,114,111,109,32,41,9,114,6,0,0, - 0,114,4,0,0,0,114,99,0,0,0,218,9,69,120,99, - 101,112,116,105,111,110,218,8,95,95,115,112,101,99,95,95, - 218,14,65,116,116,114,105,98,117,116,101,69,114,114,111,114, - 218,22,95,109,111,100,117,108,101,95,114,101,112,114,95,102, - 114,111,109,95,115,112,101,99,114,1,0,0,0,218,8,95, - 95,102,105,108,101,95,95,41,5,114,96,0,0,0,218,6, - 108,111,97,100,101,114,114,95,0,0,0,114,17,0,0,0, - 218,8,102,105,108,101,110,97,109,101,114,10,0,0,0,114, - 10,0,0,0,114,11,0,0,0,218,12,95,109,111,100,117, - 108,101,95,114,101,112,114,13,1,0,0,115,46,0,0,0, - 0,2,12,1,10,4,2,1,12,1,14,1,6,1,2,1, - 10,1,14,1,6,2,8,1,8,4,2,1,10,1,14,1, - 10,1,2,1,10,1,14,1,8,1,16,2,28,2,114,113, - 0,0,0,99,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,4,0,0,0,64,0,0,0,115,114,0,0, - 0,101,0,90,1,100,0,90,2,100,1,90,3,100,2,100, - 2,100,2,100,3,156,3,100,4,100,5,132,2,90,4,100, - 6,100,7,132,0,90,5,100,8,100,9,132,0,90,6,101, - 7,100,10,100,11,132,0,131,1,90,8,101,8,106,9,100, - 12,100,11,132,0,131,1,90,8,101,7,100,13,100,14,132, - 0,131,1,90,10,101,7,100,15,100,16,132,0,131,1,90, - 11,101,11,106,9,100,17,100,16,132,0,131,1,90,11,100, - 2,83,0,41,18,218,10,77,111,100,117,108,101,83,112,101, - 99,97,208,5,0,0,84,104,101,32,115,112,101,99,105,102, - 105,99,97,116,105,111,110,32,102,111,114,32,97,32,109,111, - 100,117,108,101,44,32,117,115,101,100,32,102,111,114,32,108, - 111,97,100,105,110,103,46,10,10,32,32,32,32,65,32,109, - 111,100,117,108,101,39,115,32,115,112,101,99,32,105,115,32, - 116,104,101,32,115,111,117,114,99,101,32,102,111,114,32,105, - 110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116, - 32,116,104,101,32,109,111,100,117,108,101,46,32,32,70,111, - 114,10,32,32,32,32,100,97,116,97,32,97,115,115,111,99, - 105,97,116,101,100,32,119,105,116,104,32,116,104,101,32,109, - 111,100,117,108,101,44,32,105,110,99,108,117,100,105,110,103, - 32,115,111,117,114,99,101,44,32,117,115,101,32,116,104,101, - 32,115,112,101,99,39,115,10,32,32,32,32,108,111,97,100, - 101,114,46,10,10,32,32,32,32,96,110,97,109,101,96,32, - 105,115,32,116,104,101,32,97,98,115,111,108,117,116,101,32, - 110,97,109,101,32,111,102,32,116,104,101,32,109,111,100,117, - 108,101,46,32,32,96,108,111,97,100,101,114,96,32,105,115, - 32,116,104,101,32,108,111,97,100,101,114,10,32,32,32,32, - 116,111,32,117,115,101,32,119,104,101,110,32,108,111,97,100, - 105,110,103,32,116,104,101,32,109,111,100,117,108,101,46,32, - 32,96,112,97,114,101,110,116,96,32,105,115,32,116,104,101, - 32,110,97,109,101,32,111,102,32,116,104,101,10,32,32,32, - 32,112,97,99,107,97,103,101,32,116,104,101,32,109,111,100, - 117,108,101,32,105,115,32,105,110,46,32,32,84,104,101,32, - 112,97,114,101,110,116,32,105,115,32,100,101,114,105,118,101, - 100,32,102,114,111,109,32,116,104,101,32,110,97,109,101,46, - 10,10,32,32,32,32,96,105,115,95,112,97,99,107,97,103, - 101,96,32,100,101,116,101,114,109,105,110,101,115,32,105,102, - 32,116,104,101,32,109,111,100,117,108,101,32,105,115,32,99, - 111,110,115,105,100,101,114,101,100,32,97,32,112,97,99,107, - 97,103,101,32,111,114,10,32,32,32,32,110,111,116,46,32, - 32,79,110,32,109,111,100,117,108,101,115,32,116,104,105,115, - 32,105,115,32,114,101,102,108,101,99,116,101,100,32,98,121, - 32,116,104,101,32,96,95,95,112,97,116,104,95,95,96,32, - 97,116,116,114,105,98,117,116,101,46,10,10,32,32,32,32, - 96,111,114,105,103,105,110,96,32,105,115,32,116,104,101,32, - 115,112,101,99,105,102,105,99,32,108,111,99,97,116,105,111, - 110,32,117,115,101,100,32,98,121,32,116,104,101,32,108,111, - 97,100,101,114,32,102,114,111,109,32,119,104,105,99,104,32, - 116,111,10,32,32,32,32,108,111,97,100,32,116,104,101,32, - 109,111,100,117,108,101,44,32,105,102,32,116,104,97,116,32, - 105,110,102,111,114,109,97,116,105,111,110,32,105,115,32,97, - 118,97,105,108,97,98,108,101,46,32,32,87,104,101,110,32, - 102,105,108,101,110,97,109,101,32,105,115,10,32,32,32,32, - 115,101,116,44,32,111,114,105,103,105,110,32,119,105,108,108, - 32,109,97,116,99,104,46,10,10,32,32,32,32,96,104,97, - 115,95,108,111,99,97,116,105,111,110,96,32,105,110,100,105, - 99,97,116,101,115,32,116,104,97,116,32,97,32,115,112,101, - 99,39,115,32,34,111,114,105,103,105,110,34,32,114,101,102, - 108,101,99,116,115,32,97,32,108,111,99,97,116,105,111,110, - 46,10,32,32,32,32,87,104,101,110,32,116,104,105,115,32, - 105,115,32,84,114,117,101,44,32,96,95,95,102,105,108,101, - 95,95,96,32,97,116,116,114,105,98,117,116,101,32,111,102, - 32,116,104,101,32,109,111,100,117,108,101,32,105,115,32,115, - 101,116,46,10,10,32,32,32,32,96,99,97,99,104,101,100, - 96,32,105,115,32,116,104,101,32,108,111,99,97,116,105,111, - 110,32,111,102,32,116,104,101,32,99,97,99,104,101,100,32, - 98,121,116,101,99,111,100,101,32,102,105,108,101,44,32,105, - 102,32,97,110,121,46,32,32,73,116,10,32,32,32,32,99, - 111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104, - 101,32,96,95,95,99,97,99,104,101,100,95,95,96,32,97, - 116,116,114,105,98,117,116,101,46,10,10,32,32,32,32,96, - 115,117,98,109,111,100,117,108,101,95,115,101,97,114,99,104, - 95,108,111,99,97,116,105,111,110,115,96,32,105,115,32,116, - 104,101,32,115,101,113,117,101,110,99,101,32,111,102,32,112, - 97,116,104,32,101,110,116,114,105,101,115,32,116,111,10,32, - 32,32,32,115,101,97,114,99,104,32,119,104,101,110,32,105, - 109,112,111,114,116,105,110,103,32,115,117,98,109,111,100,117, - 108,101,115,46,32,32,73,102,32,115,101,116,44,32,105,115, - 95,112,97,99,107,97,103,101,32,115,104,111,117,108,100,32, - 98,101,10,32,32,32,32,84,114,117,101,45,45,97,110,100, - 32,70,97,108,115,101,32,111,116,104,101,114,119,105,115,101, - 46,10,10,32,32,32,32,80,97,99,107,97,103,101,115,32, - 97,114,101,32,115,105,109,112,108,121,32,109,111,100,117,108, - 101,115,32,116,104,97,116,32,40,109,97,121,41,32,104,97, - 118,101,32,115,117,98,109,111,100,117,108,101,115,46,32,32, - 73,102,32,97,32,115,112,101,99,10,32,32,32,32,104,97, - 115,32,97,32,110,111,110,45,78,111,110,101,32,118,97,108, - 117,101,32,105,110,32,96,115,117,98,109,111,100,117,108,101, - 95,115,101,97,114,99,104,95,108,111,99,97,116,105,111,110, - 115,96,44,32,116,104,101,32,105,109,112,111,114,116,10,32, - 32,32,32,115,121,115,116,101,109,32,119,105,108,108,32,99, - 111,110,115,105,100,101,114,32,109,111,100,117,108,101,115,32, - 108,111,97,100,101,100,32,102,114,111,109,32,116,104,101,32, - 115,112,101,99,32,97,115,32,112,97,99,107,97,103,101,115, - 46,10,10,32,32,32,32,79,110,108,121,32,102,105,110,100, - 101,114,115,32,40,115,101,101,32,105,109,112,111,114,116,108, - 105,98,46,97,98,99,46,77,101,116,97,80,97,116,104,70, - 105,110,100,101,114,32,97,110,100,10,32,32,32,32,105,109, - 112,111,114,116,108,105,98,46,97,98,99,46,80,97,116,104, - 69,110,116,114,121,70,105,110,100,101,114,41,32,115,104,111, - 117,108,100,32,109,111,100,105,102,121,32,77,111,100,117,108, - 101,83,112,101,99,32,105,110,115,116,97,110,99,101,115,46, - 10,10,32,32,32,32,78,41,3,218,6,111,114,105,103,105, - 110,218,12,108,111,97,100,101,114,95,115,116,97,116,101,218, - 10,105,115,95,112,97,99,107,97,103,101,99,3,0,0,0, - 0,0,0,0,3,0,0,0,6,0,0,0,2,0,0,0, - 67,0,0,0,115,54,0,0,0,124,1,124,0,95,0,124, - 2,124,0,95,1,124,3,124,0,95,2,124,4,124,0,95, - 3,124,5,114,32,103,0,110,2,100,0,124,0,95,4,100, - 1,124,0,95,5,100,0,124,0,95,6,100,0,83,0,41, - 2,78,70,41,7,114,17,0,0,0,114,111,0,0,0,114, - 115,0,0,0,114,116,0,0,0,218,26,115,117,98,109,111, - 100,117,108,101,95,115,101,97,114,99,104,95,108,111,99,97, - 116,105,111,110,115,218,13,95,115,101,116,95,102,105,108,101, - 97,116,116,114,218,7,95,99,97,99,104,101,100,41,6,114, - 30,0,0,0,114,17,0,0,0,114,111,0,0,0,114,115, - 0,0,0,114,116,0,0,0,114,117,0,0,0,114,10,0, - 0,0,114,10,0,0,0,114,11,0,0,0,114,31,0,0, - 0,86,1,0,0,115,14,0,0,0,0,2,6,1,6,1, - 6,1,6,1,14,3,6,1,122,19,77,111,100,117,108,101, - 83,112,101,99,46,95,95,105,110,105,116,95,95,99,1,0, - 0,0,0,0,0,0,0,0,0,0,2,0,0,0,5,0, - 0,0,67,0,0,0,115,106,0,0,0,100,1,124,0,106, - 0,155,2,157,2,100,2,124,0,106,1,155,2,157,2,103, - 2,125,1,124,0,106,2,100,0,107,9,114,52,124,1,160, - 3,100,3,124,0,106,2,155,2,157,2,161,1,1,0,124, - 0,106,4,100,0,107,9,114,80,124,1,160,3,100,4,124, - 0,106,4,155,0,157,2,161,1,1,0,124,0,106,5,106, - 6,155,0,100,5,100,6,160,7,124,1,161,1,155,0,100, - 7,157,4,83,0,41,8,78,122,5,110,97,109,101,61,122, - 7,108,111,97,100,101,114,61,122,7,111,114,105,103,105,110, - 61,122,27,115,117,98,109,111,100,117,108,101,95,115,101,97, - 114,99,104,95,108,111,99,97,116,105,111,110,115,61,250,1, - 40,122,2,44,32,250,1,41,41,8,114,17,0,0,0,114, - 111,0,0,0,114,115,0,0,0,218,6,97,112,112,101,110, - 100,114,118,0,0,0,218,9,95,95,99,108,97,115,115,95, - 95,114,1,0,0,0,218,4,106,111,105,110,41,2,114,30, - 0,0,0,114,54,0,0,0,114,10,0,0,0,114,10,0, - 0,0,114,11,0,0,0,114,47,0,0,0,98,1,0,0, - 115,16,0,0,0,0,1,10,1,10,255,4,2,10,1,18, - 1,10,1,18,1,122,19,77,111,100,117,108,101,83,112,101, - 99,46,95,95,114,101,112,114,95,95,99,2,0,0,0,0, - 0,0,0,0,0,0,0,3,0,0,0,8,0,0,0,67, - 0,0,0,115,108,0,0,0,124,0,106,0,125,2,122,72, - 124,0,106,1,124,1,106,1,107,2,111,76,124,0,106,2, - 124,1,106,2,107,2,111,76,124,0,106,3,124,1,106,3, - 107,2,111,76,124,2,124,1,106,0,107,2,111,76,124,0, - 106,4,124,1,106,4,107,2,111,76,124,0,106,5,124,1, - 106,5,107,2,87,0,83,0,4,0,116,6,107,10,114,102, - 1,0,1,0,1,0,116,7,6,0,89,0,83,0,88,0, - 100,0,83,0,114,13,0,0,0,41,8,114,118,0,0,0, - 114,17,0,0,0,114,111,0,0,0,114,115,0,0,0,218, - 6,99,97,99,104,101,100,218,12,104,97,115,95,108,111,99, - 97,116,105,111,110,114,108,0,0,0,218,14,78,111,116,73, - 109,112,108,101,109,101,110,116,101,100,41,3,114,30,0,0, - 0,90,5,111,116,104,101,114,90,4,115,109,115,108,114,10, - 0,0,0,114,10,0,0,0,114,11,0,0,0,218,6,95, - 95,101,113,95,95,107,1,0,0,115,30,0,0,0,0,1, - 6,1,2,1,12,1,10,255,2,2,10,254,2,3,8,253, - 2,4,10,252,2,5,10,251,4,6,14,1,122,17,77,111, - 100,117,108,101,83,112,101,99,46,95,95,101,113,95,95,99, - 1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, - 3,0,0,0,67,0,0,0,115,58,0,0,0,124,0,106, - 0,100,0,107,8,114,52,124,0,106,1,100,0,107,9,114, - 52,124,0,106,2,114,52,116,3,100,0,107,8,114,38,116, - 4,130,1,116,3,160,5,124,0,106,1,161,1,124,0,95, - 0,124,0,106,0,83,0,114,13,0,0,0,41,6,114,120, - 0,0,0,114,115,0,0,0,114,119,0,0,0,218,19,95, - 98,111,111,116,115,116,114,97,112,95,101,120,116,101,114,110, - 97,108,218,19,78,111,116,73,109,112,108,101,109,101,110,116, - 101,100,69,114,114,111,114,90,11,95,103,101,116,95,99,97, - 99,104,101,100,114,46,0,0,0,114,10,0,0,0,114,10, - 0,0,0,114,11,0,0,0,114,126,0,0,0,119,1,0, - 0,115,12,0,0,0,0,2,10,1,16,1,8,1,4,1, - 14,1,122,17,77,111,100,117,108,101,83,112,101,99,46,99, - 97,99,104,101,100,99,2,0,0,0,0,0,0,0,0,0, - 0,0,2,0,0,0,2,0,0,0,67,0,0,0,115,10, - 0,0,0,124,1,124,0,95,0,100,0,83,0,114,13,0, - 0,0,41,1,114,120,0,0,0,41,2,114,30,0,0,0, - 114,126,0,0,0,114,10,0,0,0,114,10,0,0,0,114, - 11,0,0,0,114,126,0,0,0,128,1,0,0,115,2,0, - 0,0,0,2,99,1,0,0,0,0,0,0,0,0,0,0, - 0,1,0,0,0,3,0,0,0,67,0,0,0,115,36,0, - 0,0,124,0,106,0,100,1,107,8,114,26,124,0,106,1, - 160,2,100,2,161,1,100,3,25,0,83,0,124,0,106,1, - 83,0,100,1,83,0,41,4,122,32,84,104,101,32,110,97, - 109,101,32,111,102,32,116,104,101,32,109,111,100,117,108,101, - 39,115,32,112,97,114,101,110,116,46,78,218,1,46,114,22, - 0,0,0,41,3,114,118,0,0,0,114,17,0,0,0,218, - 10,114,112,97,114,116,105,116,105,111,110,114,46,0,0,0, - 114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,218, - 6,112,97,114,101,110,116,132,1,0,0,115,6,0,0,0, - 0,3,10,1,16,2,122,17,77,111,100,117,108,101,83,112, - 101,99,46,112,97,114,101,110,116,99,1,0,0,0,0,0, - 0,0,0,0,0,0,1,0,0,0,1,0,0,0,67,0, - 0,0,115,6,0,0,0,124,0,106,0,83,0,114,13,0, - 0,0,41,1,114,119,0,0,0,114,46,0,0,0,114,10, - 0,0,0,114,10,0,0,0,114,11,0,0,0,114,127,0, - 0,0,140,1,0,0,115,2,0,0,0,0,2,122,23,77, - 111,100,117,108,101,83,112,101,99,46,104,97,115,95,108,111, - 99,97,116,105,111,110,99,2,0,0,0,0,0,0,0,0, - 0,0,0,2,0,0,0,2,0,0,0,67,0,0,0,115, - 14,0,0,0,116,0,124,1,131,1,124,0,95,1,100,0, - 83,0,114,13,0,0,0,41,2,218,4,98,111,111,108,114, - 119,0,0,0,41,2,114,30,0,0,0,218,5,118,97,108, - 117,101,114,10,0,0,0,114,10,0,0,0,114,11,0,0, - 0,114,127,0,0,0,144,1,0,0,115,2,0,0,0,0, - 2,41,12,114,1,0,0,0,114,0,0,0,0,114,2,0, - 0,0,114,3,0,0,0,114,31,0,0,0,114,47,0,0, - 0,114,129,0,0,0,218,8,112,114,111,112,101,114,116,121, - 114,126,0,0,0,218,6,115,101,116,116,101,114,114,134,0, - 0,0,114,127,0,0,0,114,10,0,0,0,114,10,0,0, - 0,114,10,0,0,0,114,11,0,0,0,114,114,0,0,0, - 49,1,0,0,115,32,0,0,0,8,1,4,36,4,1,2, - 255,12,12,8,9,8,12,2,1,10,8,4,1,10,3,2, - 1,10,7,2,1,10,3,4,1,114,114,0,0,0,169,2, - 114,115,0,0,0,114,117,0,0,0,99,2,0,0,0,0, - 0,0,0,2,0,0,0,6,0,0,0,8,0,0,0,67, - 0,0,0,115,154,0,0,0,116,0,124,1,100,1,131,2, - 114,74,116,1,100,2,107,8,114,22,116,2,130,1,116,1, - 106,3,125,4,124,3,100,2,107,8,114,48,124,4,124,0, - 124,1,100,3,141,2,83,0,124,3,114,56,103,0,110,2, - 100,2,125,5,124,4,124,0,124,1,124,5,100,4,141,3, - 83,0,124,3,100,2,107,8,114,138,116,0,124,1,100,5, - 131,2,114,134,122,14,124,1,160,4,124,0,161,1,125,3, - 87,0,113,138,4,0,116,5,107,10,114,130,1,0,1,0, - 1,0,100,2,125,3,89,0,113,138,88,0,110,4,100,6, - 125,3,116,6,124,0,124,1,124,2,124,3,100,7,141,4, - 83,0,41,8,122,53,82,101,116,117,114,110,32,97,32,109, - 111,100,117,108,101,32,115,112,101,99,32,98,97,115,101,100, - 32,111,110,32,118,97,114,105,111,117,115,32,108,111,97,100, - 101,114,32,109,101,116,104,111,100,115,46,90,12,103,101,116, - 95,102,105,108,101,110,97,109,101,78,41,1,114,111,0,0, - 0,41,2,114,111,0,0,0,114,118,0,0,0,114,117,0, - 0,0,70,114,139,0,0,0,41,7,114,4,0,0,0,114, - 130,0,0,0,114,131,0,0,0,218,23,115,112,101,99,95, - 102,114,111,109,95,102,105,108,101,95,108,111,99,97,116,105, - 111,110,114,117,0,0,0,114,79,0,0,0,114,114,0,0, - 0,41,6,114,17,0,0,0,114,111,0,0,0,114,115,0, - 0,0,114,117,0,0,0,114,140,0,0,0,90,6,115,101, - 97,114,99,104,114,10,0,0,0,114,10,0,0,0,114,11, - 0,0,0,114,91,0,0,0,149,1,0,0,115,36,0,0, - 0,0,2,10,1,8,1,4,1,6,2,8,1,12,1,12, - 1,6,1,2,255,6,3,8,1,10,1,2,1,14,1,14, - 1,12,3,4,2,114,91,0,0,0,99,3,0,0,0,0, - 0,0,0,0,0,0,0,8,0,0,0,8,0,0,0,67, - 0,0,0,115,56,1,0,0,122,10,124,0,106,0,125,3, - 87,0,110,20,4,0,116,1,107,10,114,30,1,0,1,0, - 1,0,89,0,110,14,88,0,124,3,100,0,107,9,114,44, - 124,3,83,0,124,0,106,2,125,4,124,1,100,0,107,8, - 114,90,122,10,124,0,106,3,125,1,87,0,110,20,4,0, - 116,1,107,10,114,88,1,0,1,0,1,0,89,0,110,2, - 88,0,122,10,124,0,106,4,125,5,87,0,110,24,4,0, - 116,1,107,10,114,124,1,0,1,0,1,0,100,0,125,5, - 89,0,110,2,88,0,124,2,100,0,107,8,114,184,124,5, - 100,0,107,8,114,180,122,10,124,1,106,5,125,2,87,0, - 113,184,4,0,116,1,107,10,114,176,1,0,1,0,1,0, - 100,0,125,2,89,0,113,184,88,0,110,4,124,5,125,2, - 122,10,124,0,106,6,125,6,87,0,110,24,4,0,116,1, - 107,10,114,218,1,0,1,0,1,0,100,0,125,6,89,0, - 110,2,88,0,122,14,116,7,124,0,106,8,131,1,125,7, - 87,0,110,26,4,0,116,1,107,10,144,1,114,4,1,0, - 1,0,1,0,100,0,125,7,89,0,110,2,88,0,116,9, - 124,4,124,1,124,2,100,1,141,3,125,3,124,5,100,0, - 107,8,144,1,114,34,100,2,110,2,100,3,124,3,95,10, - 124,6,124,3,95,11,124,7,124,3,95,12,124,3,83,0, - 41,4,78,169,1,114,115,0,0,0,70,84,41,13,114,107, - 0,0,0,114,108,0,0,0,114,1,0,0,0,114,98,0, - 0,0,114,110,0,0,0,218,7,95,79,82,73,71,73,78, - 218,10,95,95,99,97,99,104,101,100,95,95,218,4,108,105, - 115,116,218,8,95,95,112,97,116,104,95,95,114,114,0,0, - 0,114,119,0,0,0,114,126,0,0,0,114,118,0,0,0, - 41,8,114,96,0,0,0,114,111,0,0,0,114,115,0,0, - 0,114,95,0,0,0,114,17,0,0,0,90,8,108,111,99, - 97,116,105,111,110,114,126,0,0,0,114,118,0,0,0,114, - 10,0,0,0,114,10,0,0,0,114,11,0,0,0,218,17, - 95,115,112,101,99,95,102,114,111,109,95,109,111,100,117,108, - 101,175,1,0,0,115,72,0,0,0,0,2,2,1,10,1, - 14,1,6,2,8,1,4,2,6,1,8,1,2,1,10,1, - 14,2,6,1,2,1,10,1,14,1,10,1,8,1,8,1, - 2,1,10,1,14,1,12,2,4,1,2,1,10,1,14,1, - 10,1,2,1,14,1,16,1,10,2,14,1,20,1,6,1, - 6,1,114,146,0,0,0,70,169,1,218,8,111,118,101,114, - 114,105,100,101,99,2,0,0,0,0,0,0,0,1,0,0, - 0,5,0,0,0,8,0,0,0,67,0,0,0,115,226,1, - 0,0,124,2,115,20,116,0,124,1,100,1,100,0,131,3, - 100,0,107,8,114,54,122,12,124,0,106,1,124,1,95,2, - 87,0,110,20,4,0,116,3,107,10,114,52,1,0,1,0, - 1,0,89,0,110,2,88,0,124,2,115,74,116,0,124,1, - 100,2,100,0,131,3,100,0,107,8,114,178,124,0,106,4, - 125,3,124,3,100,0,107,8,114,146,124,0,106,5,100,0, - 107,9,114,146,116,6,100,0,107,8,114,110,116,7,130,1, - 116,6,106,8,125,4,124,4,160,9,124,4,161,1,125,3, - 124,0,106,5,124,3,95,10,124,3,124,0,95,4,100,0, - 124,1,95,11,122,10,124,3,124,1,95,12,87,0,110,20, - 4,0,116,3,107,10,114,176,1,0,1,0,1,0,89,0, - 110,2,88,0,124,2,115,198,116,0,124,1,100,3,100,0, - 131,3,100,0,107,8,114,232,122,12,124,0,106,13,124,1, - 95,14,87,0,110,20,4,0,116,3,107,10,114,230,1,0, - 1,0,1,0,89,0,110,2,88,0,122,10,124,0,124,1, - 95,15,87,0,110,22,4,0,116,3,107,10,144,1,114,8, - 1,0,1,0,1,0,89,0,110,2,88,0,124,2,144,1, - 115,34,116,0,124,1,100,4,100,0,131,3,100,0,107,8, - 144,1,114,82,124,0,106,5,100,0,107,9,144,1,114,82, - 122,12,124,0,106,5,124,1,95,16,87,0,110,22,4,0, - 116,3,107,10,144,1,114,80,1,0,1,0,1,0,89,0, - 110,2,88,0,124,0,106,17,144,1,114,222,124,2,144,1, - 115,114,116,0,124,1,100,5,100,0,131,3,100,0,107,8, - 144,1,114,150,122,12,124,0,106,18,124,1,95,11,87,0, - 110,22,4,0,116,3,107,10,144,1,114,148,1,0,1,0, - 1,0,89,0,110,2,88,0,124,2,144,1,115,174,116,0, - 124,1,100,6,100,0,131,3,100,0,107,8,144,1,114,222, - 124,0,106,19,100,0,107,9,144,1,114,222,122,12,124,0, - 106,19,124,1,95,20,87,0,110,22,4,0,116,3,107,10, - 144,1,114,220,1,0,1,0,1,0,89,0,110,2,88,0, - 124,1,83,0,41,7,78,114,1,0,0,0,114,98,0,0, - 0,218,11,95,95,112,97,99,107,97,103,101,95,95,114,145, - 0,0,0,114,110,0,0,0,114,143,0,0,0,41,21,114, - 6,0,0,0,114,17,0,0,0,114,1,0,0,0,114,108, - 0,0,0,114,111,0,0,0,114,118,0,0,0,114,130,0, - 0,0,114,131,0,0,0,218,16,95,78,97,109,101,115,112, - 97,99,101,76,111,97,100,101,114,218,7,95,95,110,101,119, - 95,95,90,5,95,112,97,116,104,114,110,0,0,0,114,98, - 0,0,0,114,134,0,0,0,114,149,0,0,0,114,107,0, - 0,0,114,145,0,0,0,114,127,0,0,0,114,115,0,0, - 0,114,126,0,0,0,114,143,0,0,0,41,5,114,95,0, - 0,0,114,96,0,0,0,114,148,0,0,0,114,111,0,0, - 0,114,150,0,0,0,114,10,0,0,0,114,10,0,0,0, - 114,11,0,0,0,218,18,95,105,110,105,116,95,109,111,100, - 117,108,101,95,97,116,116,114,115,220,1,0,0,115,96,0, - 0,0,0,4,20,1,2,1,12,1,14,1,6,2,20,1, - 6,1,8,2,10,1,8,1,4,1,6,2,10,1,8,1, - 6,11,6,1,2,1,10,1,14,1,6,2,20,1,2,1, - 12,1,14,1,6,2,2,1,10,1,16,1,6,2,24,1, - 12,1,2,1,12,1,16,1,6,2,8,1,24,1,2,1, - 12,1,16,1,6,2,24,1,12,1,2,1,12,1,16,1, - 6,1,114,152,0,0,0,99,1,0,0,0,0,0,0,0, - 0,0,0,0,2,0,0,0,3,0,0,0,67,0,0,0, - 115,82,0,0,0,100,1,125,1,116,0,124,0,106,1,100, - 2,131,2,114,30,124,0,106,1,160,2,124,0,161,1,125, - 1,110,20,116,0,124,0,106,1,100,3,131,2,114,50,116, - 3,100,4,131,1,130,1,124,1,100,1,107,8,114,68,116, - 4,124,0,106,5,131,1,125,1,116,6,124,0,124,1,131, - 2,1,0,124,1,83,0,41,5,122,43,67,114,101,97,116, - 101,32,97,32,109,111,100,117,108,101,32,98,97,115,101,100, - 32,111,110,32,116,104,101,32,112,114,111,118,105,100,101,100, - 32,115,112,101,99,46,78,218,13,99,114,101,97,116,101,95, - 109,111,100,117,108,101,218,11,101,120,101,99,95,109,111,100, - 117,108,101,122,66,108,111,97,100,101,114,115,32,116,104,97, - 116,32,100,101,102,105,110,101,32,101,120,101,99,95,109,111, - 100,117,108,101,40,41,32,109,117,115,116,32,97,108,115,111, - 32,100,101,102,105,110,101,32,99,114,101,97,116,101,95,109, - 111,100,117,108,101,40,41,41,7,114,4,0,0,0,114,111, - 0,0,0,114,153,0,0,0,114,79,0,0,0,114,18,0, - 0,0,114,17,0,0,0,114,152,0,0,0,169,2,114,95, - 0,0,0,114,96,0,0,0,114,10,0,0,0,114,10,0, - 0,0,114,11,0,0,0,218,16,109,111,100,117,108,101,95, - 102,114,111,109,95,115,112,101,99,36,2,0,0,115,18,0, - 0,0,0,3,4,1,12,3,14,1,12,1,8,2,8,1, - 10,1,10,1,114,156,0,0,0,99,1,0,0,0,0,0, - 0,0,0,0,0,0,2,0,0,0,5,0,0,0,67,0, - 0,0,115,126,0,0,0,124,0,106,0,100,1,107,8,114, - 14,100,2,110,4,124,0,106,0,125,1,124,0,106,1,100, - 1,107,8,114,74,124,0,106,2,100,1,107,8,114,52,100, - 3,124,1,155,2,100,4,157,3,83,0,100,3,124,1,155, - 2,100,5,124,0,106,2,155,2,100,6,157,5,83,0,110, - 48,124,0,106,3,114,100,100,3,124,1,155,2,100,7,124, - 0,106,1,155,2,100,4,157,5,83,0,100,3,124,0,106, - 0,155,2,100,5,124,0,106,1,155,0,100,6,157,5,83, - 0,100,1,83,0,41,8,122,38,82,101,116,117,114,110,32, - 116,104,101,32,114,101,112,114,32,116,111,32,117,115,101,32, - 102,111,114,32,116,104,101,32,109,111,100,117,108,101,46,78, - 114,100,0,0,0,114,101,0,0,0,114,102,0,0,0,114, - 103,0,0,0,114,104,0,0,0,114,105,0,0,0,41,4, - 114,17,0,0,0,114,115,0,0,0,114,111,0,0,0,114, - 127,0,0,0,41,2,114,95,0,0,0,114,17,0,0,0, - 114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,114, - 109,0,0,0,53,2,0,0,115,16,0,0,0,0,3,20, - 1,10,1,10,1,12,2,22,2,6,1,20,2,114,109,0, - 0,0,99,2,0,0,0,0,0,0,0,0,0,0,0,4, - 0,0,0,10,0,0,0,67,0,0,0,115,206,0,0,0, - 124,0,106,0,125,2,116,1,124,2,131,1,143,182,1,0, - 116,2,106,3,160,4,124,2,161,1,124,1,107,9,114,56, - 100,1,124,2,155,2,100,2,157,3,125,3,116,5,124,3, - 124,2,100,3,141,2,130,1,122,106,124,0,106,7,100,4, - 107,8,114,108,124,0,106,8,100,4,107,8,114,92,116,5, - 100,5,124,0,106,0,100,3,141,2,130,1,116,9,124,0, - 124,1,100,6,100,7,141,3,1,0,110,52,116,9,124,0, - 124,1,100,6,100,7,141,3,1,0,116,10,124,0,106,7, - 100,8,131,2,115,148,124,0,106,7,160,11,124,2,161,1, - 1,0,110,12,124,0,106,7,160,12,124,1,161,1,1,0, - 87,0,53,0,116,2,106,3,160,6,124,0,106,0,161,1, - 125,1,124,1,116,2,106,3,124,0,106,0,60,0,88,0, - 87,0,53,0,81,0,82,0,88,0,124,1,83,0,41,9, - 122,70,69,120,101,99,117,116,101,32,116,104,101,32,115,112, - 101,99,39,115,32,115,112,101,99,105,102,105,101,100,32,109, - 111,100,117,108,101,32,105,110,32,97,110,32,101,120,105,115, - 116,105,110,103,32,109,111,100,117,108,101,39,115,32,110,97, - 109,101,115,112,97,99,101,46,122,7,109,111,100,117,108,101, - 32,122,19,32,110,111,116,32,105,110,32,115,121,115,46,109, - 111,100,117,108,101,115,114,16,0,0,0,78,250,14,109,105, - 115,115,105,110,103,32,108,111,97,100,101,114,84,114,147,0, - 0,0,114,154,0,0,0,41,13,114,17,0,0,0,114,49, - 0,0,0,114,15,0,0,0,114,92,0,0,0,114,34,0, - 0,0,114,79,0,0,0,218,3,112,111,112,114,111,0,0, - 0,114,118,0,0,0,114,152,0,0,0,114,4,0,0,0, - 218,11,108,111,97,100,95,109,111,100,117,108,101,114,154,0, - 0,0,41,4,114,95,0,0,0,114,96,0,0,0,114,17, - 0,0,0,218,3,109,115,103,114,10,0,0,0,114,10,0, - 0,0,114,11,0,0,0,114,93,0,0,0,70,2,0,0, - 115,34,0,0,0,0,2,6,1,10,1,16,1,12,1,12, - 1,2,1,10,1,10,1,14,2,16,2,14,1,12,4,14, - 2,16,4,14,1,24,1,114,93,0,0,0,99,1,0,0, - 0,0,0,0,0,0,0,0,0,2,0,0,0,8,0,0, - 0,67,0,0,0,115,26,1,0,0,122,18,124,0,106,0, - 160,1,124,0,106,2,161,1,1,0,87,0,110,52,1,0, - 1,0,1,0,124,0,106,2,116,3,106,4,107,6,114,64, - 116,3,106,4,160,5,124,0,106,2,161,1,125,1,124,1, - 116,3,106,4,124,0,106,2,60,0,130,0,89,0,110,2, - 88,0,116,3,106,4,160,5,124,0,106,2,161,1,125,1, - 124,1,116,3,106,4,124,0,106,2,60,0,116,6,124,1, - 100,1,100,0,131,3,100,0,107,8,114,148,122,12,124,0, - 106,0,124,1,95,7,87,0,110,20,4,0,116,8,107,10, - 114,146,1,0,1,0,1,0,89,0,110,2,88,0,116,6, - 124,1,100,2,100,0,131,3,100,0,107,8,114,226,122,40, - 124,1,106,9,124,1,95,10,116,11,124,1,100,3,131,2, - 115,202,124,0,106,2,160,12,100,4,161,1,100,5,25,0, - 124,1,95,10,87,0,110,20,4,0,116,8,107,10,114,224, - 1,0,1,0,1,0,89,0,110,2,88,0,116,6,124,1, - 100,6,100,0,131,3,100,0,107,8,144,1,114,22,122,10, - 124,0,124,1,95,13,87,0,110,22,4,0,116,8,107,10, - 144,1,114,20,1,0,1,0,1,0,89,0,110,2,88,0, - 124,1,83,0,41,7,78,114,98,0,0,0,114,149,0,0, - 0,114,145,0,0,0,114,132,0,0,0,114,22,0,0,0, - 114,107,0,0,0,41,14,114,111,0,0,0,114,159,0,0, - 0,114,17,0,0,0,114,15,0,0,0,114,92,0,0,0, - 114,158,0,0,0,114,6,0,0,0,114,98,0,0,0,114, - 108,0,0,0,114,1,0,0,0,114,149,0,0,0,114,4, - 0,0,0,114,133,0,0,0,114,107,0,0,0,114,155,0, - 0,0,114,10,0,0,0,114,10,0,0,0,114,11,0,0, - 0,218,25,95,108,111,97,100,95,98,97,99,107,119,97,114, - 100,95,99,111,109,112,97,116,105,98,108,101,100,2,0,0, - 115,54,0,0,0,0,4,2,1,18,1,6,1,12,1,14, - 1,12,1,8,3,14,1,12,1,16,1,2,1,12,1,14, - 1,6,1,16,1,2,4,8,1,10,1,22,1,14,1,6, - 1,18,1,2,1,10,1,16,1,6,1,114,161,0,0,0, - 99,1,0,0,0,0,0,0,0,0,0,0,0,2,0,0, - 0,11,0,0,0,67,0,0,0,115,220,0,0,0,124,0, - 106,0,100,0,107,9,114,30,116,1,124,0,106,0,100,1, - 131,2,115,30,116,2,124,0,131,1,83,0,116,3,124,0, - 131,1,125,1,100,2,124,0,95,4,122,162,124,1,116,5, - 106,6,124,0,106,7,60,0,122,52,124,0,106,0,100,0, - 107,8,114,96,124,0,106,8,100,0,107,8,114,108,116,9, - 100,4,124,0,106,7,100,5,141,2,130,1,110,12,124,0, - 106,0,160,10,124,1,161,1,1,0,87,0,110,50,1,0, - 1,0,1,0,122,14,116,5,106,6,124,0,106,7,61,0, - 87,0,110,20,4,0,116,11,107,10,114,152,1,0,1,0, - 1,0,89,0,110,2,88,0,130,0,89,0,110,2,88,0, - 116,5,106,6,160,12,124,0,106,7,161,1,125,1,124,1, - 116,5,106,6,124,0,106,7,60,0,116,13,100,6,124,0, - 106,7,124,0,106,0,131,3,1,0,87,0,53,0,100,3, - 124,0,95,4,88,0,124,1,83,0,41,7,78,114,154,0, - 0,0,84,70,114,157,0,0,0,114,16,0,0,0,122,18, - 105,109,112,111,114,116,32,123,33,114,125,32,35,32,123,33, - 114,125,41,14,114,111,0,0,0,114,4,0,0,0,114,161, - 0,0,0,114,156,0,0,0,90,13,95,105,110,105,116,105, - 97,108,105,122,105,110,103,114,15,0,0,0,114,92,0,0, - 0,114,17,0,0,0,114,118,0,0,0,114,79,0,0,0, - 114,154,0,0,0,114,62,0,0,0,114,158,0,0,0,114, - 76,0,0,0,114,155,0,0,0,114,10,0,0,0,114,10, - 0,0,0,114,11,0,0,0,218,14,95,108,111,97,100,95, - 117,110,108,111,99,107,101,100,137,2,0,0,115,46,0,0, - 0,0,2,10,2,12,1,8,2,8,5,6,1,2,1,12, - 1,2,1,10,1,10,1,16,3,16,1,6,1,2,1,14, - 1,14,1,6,1,8,5,14,1,12,1,20,2,8,2,114, - 162,0,0,0,99,1,0,0,0,0,0,0,0,0,0,0, - 0,1,0,0,0,10,0,0,0,67,0,0,0,115,42,0, - 0,0,116,0,124,0,106,1,131,1,143,22,1,0,116,2, - 124,0,131,1,87,0,2,0,53,0,81,0,82,0,163,0, - 83,0,81,0,82,0,88,0,100,1,83,0,41,2,122,191, - 82,101,116,117,114,110,32,97,32,110,101,119,32,109,111,100, - 117,108,101,32,111,98,106,101,99,116,44,32,108,111,97,100, - 101,100,32,98,121,32,116,104,101,32,115,112,101,99,39,115, - 32,108,111,97,100,101,114,46,10,10,32,32,32,32,84,104, - 101,32,109,111,100,117,108,101,32,105,115,32,110,111,116,32, - 97,100,100,101,100,32,116,111,32,105,116,115,32,112,97,114, - 101,110,116,46,10,10,32,32,32,32,73,102,32,97,32,109, - 111,100,117,108,101,32,105,115,32,97,108,114,101,97,100,121, - 32,105,110,32,115,121,115,46,109,111,100,117,108,101,115,44, - 32,116,104,97,116,32,101,120,105,115,116,105,110,103,32,109, - 111,100,117,108,101,32,103,101,116,115,10,32,32,32,32,99, - 108,111,98,98,101,114,101,100,46,10,10,32,32,32,32,78, - 41,3,114,49,0,0,0,114,17,0,0,0,114,162,0,0, - 0,41,1,114,95,0,0,0,114,10,0,0,0,114,10,0, - 0,0,114,11,0,0,0,114,94,0,0,0,179,2,0,0, - 115,4,0,0,0,0,9,12,1,114,94,0,0,0,99,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4, - 0,0,0,64,0,0,0,115,140,0,0,0,101,0,90,1, - 100,0,90,2,100,1,90,3,100,2,90,4,101,5,100,3, - 100,4,132,0,131,1,90,6,101,7,100,20,100,6,100,7, - 132,1,131,1,90,8,101,7,100,21,100,8,100,9,132,1, - 131,1,90,9,101,7,100,10,100,11,132,0,131,1,90,10, - 101,7,100,12,100,13,132,0,131,1,90,11,101,7,101,12, - 100,14,100,15,132,0,131,1,131,1,90,13,101,7,101,12, - 100,16,100,17,132,0,131,1,131,1,90,14,101,7,101,12, - 100,18,100,19,132,0,131,1,131,1,90,15,101,7,101,16, - 131,1,90,17,100,5,83,0,41,22,218,15,66,117,105,108, - 116,105,110,73,109,112,111,114,116,101,114,122,144,77,101,116, - 97,32,112,97,116,104,32,105,109,112,111,114,116,32,102,111, - 114,32,98,117,105,108,116,45,105,110,32,109,111,100,117,108, - 101,115,46,10,10,32,32,32,32,65,108,108,32,109,101,116, - 104,111,100,115,32,97,114,101,32,101,105,116,104,101,114,32, - 99,108,97,115,115,32,111,114,32,115,116,97,116,105,99,32, - 109,101,116,104,111,100,115,32,116,111,32,97,118,111,105,100, - 32,116,104,101,32,110,101,101,100,32,116,111,10,32,32,32, - 32,105,110,115,116,97,110,116,105,97,116,101,32,116,104,101, - 32,99,108,97,115,115,46,10,10,32,32,32,32,122,8,98, - 117,105,108,116,45,105,110,99,1,0,0,0,0,0,0,0, - 0,0,0,0,1,0,0,0,5,0,0,0,67,0,0,0, - 115,22,0,0,0,100,1,124,0,106,0,155,2,100,2,116, - 1,106,2,155,0,100,3,157,5,83,0,169,4,122,115,82, - 101,116,117,114,110,32,114,101,112,114,32,102,111,114,32,116, - 104,101,32,109,111,100,117,108,101,46,10,10,32,32,32,32, - 32,32,32,32,84,104,101,32,109,101,116,104,111,100,32,105, - 115,32,100,101,112,114,101,99,97,116,101,100,46,32,32,84, - 104,101,32,105,109,112,111,114,116,32,109,97,99,104,105,110, - 101,114,121,32,100,111,101,115,32,116,104,101,32,106,111,98, - 32,105,116,115,101,108,102,46,10,10,32,32,32,32,32,32, - 32,32,114,101,0,0,0,114,103,0,0,0,114,104,0,0, - 0,41,3,114,1,0,0,0,114,163,0,0,0,114,142,0, - 0,0,41,1,114,96,0,0,0,114,10,0,0,0,114,10, - 0,0,0,114,11,0,0,0,114,99,0,0,0,205,2,0, - 0,115,2,0,0,0,0,7,122,27,66,117,105,108,116,105, - 110,73,109,112,111,114,116,101,114,46,109,111,100,117,108,101, - 95,114,101,112,114,78,99,4,0,0,0,0,0,0,0,0, - 0,0,0,4,0,0,0,5,0,0,0,67,0,0,0,115, - 46,0,0,0,124,2,100,0,107,9,114,12,100,0,83,0, - 116,0,160,1,124,1,161,1,114,38,116,2,124,1,124,0, - 124,0,106,3,100,1,141,3,83,0,100,0,83,0,100,0, - 83,0,169,2,78,114,141,0,0,0,41,4,114,56,0,0, - 0,90,10,105,115,95,98,117,105,108,116,105,110,114,91,0, - 0,0,114,142,0,0,0,169,4,218,3,99,108,115,114,81, - 0,0,0,218,4,112,97,116,104,218,6,116,97,114,103,101, - 116,114,10,0,0,0,114,10,0,0,0,114,11,0,0,0, - 218,9,102,105,110,100,95,115,112,101,99,214,2,0,0,115, - 10,0,0,0,0,2,8,1,4,1,10,1,16,2,122,25, - 66,117,105,108,116,105,110,73,109,112,111,114,116,101,114,46, - 102,105,110,100,95,115,112,101,99,99,3,0,0,0,0,0, - 0,0,0,0,0,0,4,0,0,0,4,0,0,0,67,0, - 0,0,115,30,0,0,0,124,0,160,0,124,1,124,2,161, - 2,125,3,124,3,100,1,107,9,114,26,124,3,106,1,83, - 0,100,1,83,0,41,2,122,175,70,105,110,100,32,116,104, - 101,32,98,117,105,108,116,45,105,110,32,109,111,100,117,108, - 101,46,10,10,32,32,32,32,32,32,32,32,73,102,32,39, - 112,97,116,104,39,32,105,115,32,101,118,101,114,32,115,112, - 101,99,105,102,105,101,100,32,116,104,101,110,32,116,104,101, - 32,115,101,97,114,99,104,32,105,115,32,99,111,110,115,105, - 100,101,114,101,100,32,97,32,102,97,105,108,117,114,101,46, - 10,10,32,32,32,32,32,32,32,32,84,104,105,115,32,109, - 101,116,104,111,100,32,105,115,32,100,101,112,114,101,99,97, - 116,101,100,46,32,32,85,115,101,32,102,105,110,100,95,115, - 112,101,99,40,41,32,105,110,115,116,101,97,100,46,10,10, - 32,32,32,32,32,32,32,32,78,41,2,114,170,0,0,0, - 114,111,0,0,0,41,4,114,167,0,0,0,114,81,0,0, - 0,114,168,0,0,0,114,95,0,0,0,114,10,0,0,0, - 114,10,0,0,0,114,11,0,0,0,218,11,102,105,110,100, - 95,109,111,100,117,108,101,223,2,0,0,115,4,0,0,0, - 0,9,12,1,122,27,66,117,105,108,116,105,110,73,109,112, - 111,114,116,101,114,46,102,105,110,100,95,109,111,100,117,108, - 101,99,2,0,0,0,0,0,0,0,0,0,0,0,2,0, - 0,0,4,0,0,0,67,0,0,0,115,46,0,0,0,124, - 1,106,0,116,1,106,2,107,7,114,34,116,3,124,1,106, - 0,155,2,100,1,157,2,124,1,106,0,100,2,141,2,130, - 1,116,4,116,5,106,6,124,1,131,2,83,0,41,3,122, - 24,67,114,101,97,116,101,32,97,32,98,117,105,108,116,45, - 105,110,32,109,111,100,117,108,101,114,77,0,0,0,114,16, - 0,0,0,41,7,114,17,0,0,0,114,15,0,0,0,114, - 78,0,0,0,114,79,0,0,0,114,66,0,0,0,114,56, - 0,0,0,90,14,99,114,101,97,116,101,95,98,117,105,108, - 116,105,110,41,2,114,30,0,0,0,114,95,0,0,0,114, - 10,0,0,0,114,10,0,0,0,114,11,0,0,0,114,153, - 0,0,0,235,2,0,0,115,10,0,0,0,0,3,12,1, - 12,1,4,255,6,2,122,29,66,117,105,108,116,105,110,73, - 109,112,111,114,116,101,114,46,99,114,101,97,116,101,95,109, - 111,100,117,108,101,99,2,0,0,0,0,0,0,0,0,0, - 0,0,2,0,0,0,3,0,0,0,67,0,0,0,115,16, - 0,0,0,116,0,116,1,106,2,124,1,131,2,1,0,100, - 1,83,0,41,2,122,22,69,120,101,99,32,97,32,98,117, - 105,108,116,45,105,110,32,109,111,100,117,108,101,78,41,3, - 114,66,0,0,0,114,56,0,0,0,90,12,101,120,101,99, - 95,98,117,105,108,116,105,110,41,2,114,30,0,0,0,114, - 96,0,0,0,114,10,0,0,0,114,10,0,0,0,114,11, - 0,0,0,114,154,0,0,0,243,2,0,0,115,2,0,0, - 0,0,3,122,27,66,117,105,108,116,105,110,73,109,112,111, - 114,116,101,114,46,101,120,101,99,95,109,111,100,117,108,101, - 99,2,0,0,0,0,0,0,0,0,0,0,0,2,0,0, - 0,1,0,0,0,67,0,0,0,115,4,0,0,0,100,1, - 83,0,41,2,122,57,82,101,116,117,114,110,32,78,111,110, - 101,32,97,115,32,98,117,105,108,116,45,105,110,32,109,111, - 100,117,108,101,115,32,100,111,32,110,111,116,32,104,97,118, - 101,32,99,111,100,101,32,111,98,106,101,99,116,115,46,78, - 114,10,0,0,0,169,2,114,167,0,0,0,114,81,0,0, - 0,114,10,0,0,0,114,10,0,0,0,114,11,0,0,0, - 218,8,103,101,116,95,99,111,100,101,248,2,0,0,115,2, - 0,0,0,0,4,122,24,66,117,105,108,116,105,110,73,109, - 112,111,114,116,101,114,46,103,101,116,95,99,111,100,101,99, - 2,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0, - 1,0,0,0,67,0,0,0,115,4,0,0,0,100,1,83, - 0,41,2,122,56,82,101,116,117,114,110,32,78,111,110,101, - 32,97,115,32,98,117,105,108,116,45,105,110,32,109,111,100, - 117,108,101,115,32,100,111,32,110,111,116,32,104,97,118,101, - 32,115,111,117,114,99,101,32,99,111,100,101,46,78,114,10, - 0,0,0,114,172,0,0,0,114,10,0,0,0,114,10,0, - 0,0,114,11,0,0,0,218,10,103,101,116,95,115,111,117, - 114,99,101,254,2,0,0,115,2,0,0,0,0,4,122,26, - 66,117,105,108,116,105,110,73,109,112,111,114,116,101,114,46, - 103,101,116,95,115,111,117,114,99,101,99,2,0,0,0,0, - 0,0,0,0,0,0,0,2,0,0,0,1,0,0,0,67, - 0,0,0,115,4,0,0,0,100,1,83,0,41,2,122,52, - 82,101,116,117,114,110,32,70,97,108,115,101,32,97,115,32, - 98,117,105,108,116,45,105,110,32,109,111,100,117,108,101,115, - 32,97,114,101,32,110,101,118,101,114,32,112,97,99,107,97, - 103,101,115,46,70,114,10,0,0,0,114,172,0,0,0,114, - 10,0,0,0,114,10,0,0,0,114,11,0,0,0,114,117, - 0,0,0,4,3,0,0,115,2,0,0,0,0,4,122,26, - 66,117,105,108,116,105,110,73,109,112,111,114,116,101,114,46, - 105,115,95,112,97,99,107,97,103,101,41,2,78,78,41,1, - 78,41,18,114,1,0,0,0,114,0,0,0,0,114,2,0, - 0,0,114,3,0,0,0,114,142,0,0,0,218,12,115,116, - 97,116,105,99,109,101,116,104,111,100,114,99,0,0,0,218, - 11,99,108,97,115,115,109,101,116,104,111,100,114,170,0,0, - 0,114,171,0,0,0,114,153,0,0,0,114,154,0,0,0, - 114,86,0,0,0,114,173,0,0,0,114,174,0,0,0,114, - 117,0,0,0,114,97,0,0,0,114,159,0,0,0,114,10, - 0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,0, - 0,0,114,163,0,0,0,194,2,0,0,115,44,0,0,0, - 8,2,4,7,4,2,2,1,10,8,2,1,12,8,2,1, - 12,11,2,1,10,7,2,1,10,4,2,1,2,1,12,4, - 2,1,2,1,12,4,2,1,2,1,12,4,114,163,0,0, - 0,99,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,4,0,0,0,64,0,0,0,115,144,0,0,0,101, - 0,90,1,100,0,90,2,100,1,90,3,100,2,90,4,101, - 5,100,3,100,4,132,0,131,1,90,6,101,7,100,22,100, - 6,100,7,132,1,131,1,90,8,101,7,100,23,100,8,100, - 9,132,1,131,1,90,9,101,7,100,10,100,11,132,0,131, - 1,90,10,101,5,100,12,100,13,132,0,131,1,90,11,101, - 7,100,14,100,15,132,0,131,1,90,12,101,7,101,13,100, - 16,100,17,132,0,131,1,131,1,90,14,101,7,101,13,100, - 18,100,19,132,0,131,1,131,1,90,15,101,7,101,13,100, - 20,100,21,132,0,131,1,131,1,90,16,100,5,83,0,41, - 24,218,14,70,114,111,122,101,110,73,109,112,111,114,116,101, - 114,122,142,77,101,116,97,32,112,97,116,104,32,105,109,112, - 111,114,116,32,102,111,114,32,102,114,111,122,101,110,32,109, - 111,100,117,108,101,115,46,10,10,32,32,32,32,65,108,108, - 32,109,101,116,104,111,100,115,32,97,114,101,32,101,105,116, - 104,101,114,32,99,108,97,115,115,32,111,114,32,115,116,97, - 116,105,99,32,109,101,116,104,111,100,115,32,116,111,32,97, - 118,111,105,100,32,116,104,101,32,110,101,101,100,32,116,111, - 10,32,32,32,32,105,110,115,116,97,110,116,105,97,116,101, - 32,116,104,101,32,99,108,97,115,115,46,10,10,32,32,32, - 32,90,6,102,114,111,122,101,110,99,1,0,0,0,0,0, - 0,0,0,0,0,0,1,0,0,0,5,0,0,0,67,0, - 0,0,115,22,0,0,0,100,1,124,0,106,0,155,2,100, - 2,116,1,106,2,155,0,100,3,157,5,83,0,114,164,0, - 0,0,41,3,114,1,0,0,0,114,177,0,0,0,114,142, - 0,0,0,41,1,218,1,109,114,10,0,0,0,114,10,0, - 0,0,114,11,0,0,0,114,99,0,0,0,24,3,0,0, - 115,2,0,0,0,0,7,122,26,70,114,111,122,101,110,73, - 109,112,111,114,116,101,114,46,109,111,100,117,108,101,95,114, - 101,112,114,78,99,4,0,0,0,0,0,0,0,0,0,0, - 0,4,0,0,0,5,0,0,0,67,0,0,0,115,34,0, - 0,0,116,0,160,1,124,1,161,1,114,26,116,2,124,1, - 124,0,124,0,106,3,100,1,141,3,83,0,100,0,83,0, - 100,0,83,0,114,165,0,0,0,41,4,114,56,0,0,0, - 114,88,0,0,0,114,91,0,0,0,114,142,0,0,0,114, - 166,0,0,0,114,10,0,0,0,114,10,0,0,0,114,11, - 0,0,0,114,170,0,0,0,33,3,0,0,115,6,0,0, - 0,0,2,10,1,16,2,122,24,70,114,111,122,101,110,73, - 109,112,111,114,116,101,114,46,102,105,110,100,95,115,112,101, - 99,99,3,0,0,0,0,0,0,0,0,0,0,0,3,0, - 0,0,3,0,0,0,67,0,0,0,115,18,0,0,0,116, - 0,160,1,124,1,161,1,114,14,124,0,83,0,100,1,83, - 0,41,2,122,93,70,105,110,100,32,97,32,102,114,111,122, - 101,110,32,109,111,100,117,108,101,46,10,10,32,32,32,32, - 32,32,32,32,84,104,105,115,32,109,101,116,104,111,100,32, - 105,115,32,100,101,112,114,101,99,97,116,101,100,46,32,32, - 85,115,101,32,102,105,110,100,95,115,112,101,99,40,41,32, - 105,110,115,116,101,97,100,46,10,10,32,32,32,32,32,32, - 32,32,78,41,2,114,56,0,0,0,114,88,0,0,0,41, - 3,114,167,0,0,0,114,81,0,0,0,114,168,0,0,0, - 114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,114, - 171,0,0,0,40,3,0,0,115,2,0,0,0,0,7,122, - 26,70,114,111,122,101,110,73,109,112,111,114,116,101,114,46, - 102,105,110,100,95,109,111,100,117,108,101,99,2,0,0,0, - 0,0,0,0,0,0,0,0,2,0,0,0,1,0,0,0, - 67,0,0,0,115,4,0,0,0,100,1,83,0,41,2,122, - 42,85,115,101,32,100,101,102,97,117,108,116,32,115,101,109, - 97,110,116,105,99,115,32,102,111,114,32,109,111,100,117,108, - 101,32,99,114,101,97,116,105,111,110,46,78,114,10,0,0, - 0,41,2,114,167,0,0,0,114,95,0,0,0,114,10,0, - 0,0,114,10,0,0,0,114,11,0,0,0,114,153,0,0, - 0,49,3,0,0,115,2,0,0,0,0,2,122,28,70,114, - 111,122,101,110,73,109,112,111,114,116,101,114,46,99,114,101, - 97,116,101,95,109,111,100,117,108,101,99,1,0,0,0,0, - 0,0,0,0,0,0,0,3,0,0,0,4,0,0,0,67, - 0,0,0,115,64,0,0,0,124,0,106,0,106,1,125,1, - 116,2,160,3,124,1,161,1,115,36,116,4,124,1,155,2, - 100,1,157,2,124,1,100,2,141,2,130,1,116,5,116,2, - 106,6,124,1,131,2,125,2,116,7,124,2,124,0,106,8, - 131,2,1,0,100,0,83,0,114,87,0,0,0,41,9,114, - 107,0,0,0,114,17,0,0,0,114,56,0,0,0,114,88, - 0,0,0,114,79,0,0,0,114,66,0,0,0,218,17,103, - 101,116,95,102,114,111,122,101,110,95,111,98,106,101,99,116, - 218,4,101,120,101,99,114,7,0,0,0,41,3,114,96,0, - 0,0,114,17,0,0,0,218,4,99,111,100,101,114,10,0, - 0,0,114,10,0,0,0,114,11,0,0,0,114,154,0,0, - 0,53,3,0,0,115,10,0,0,0,0,2,8,1,10,1, - 18,1,12,1,122,26,70,114,111,122,101,110,73,109,112,111, - 114,116,101,114,46,101,120,101,99,95,109,111,100,117,108,101, - 99,2,0,0,0,0,0,0,0,0,0,0,0,2,0,0, - 0,3,0,0,0,67,0,0,0,115,10,0,0,0,116,0, - 124,0,124,1,131,2,83,0,41,1,122,95,76,111,97,100, - 32,97,32,102,114,111,122,101,110,32,109,111,100,117,108,101, - 46,10,10,32,32,32,32,32,32,32,32,84,104,105,115,32, - 109,101,116,104,111,100,32,105,115,32,100,101,112,114,101,99, - 97,116,101,100,46,32,32,85,115,101,32,101,120,101,99,95, - 109,111,100,117,108,101,40,41,32,105,110,115,116,101,97,100, - 46,10,10,32,32,32,32,32,32,32,32,41,1,114,97,0, - 0,0,114,172,0,0,0,114,10,0,0,0,114,10,0,0, - 0,114,11,0,0,0,114,159,0,0,0,61,3,0,0,115, - 2,0,0,0,0,7,122,26,70,114,111,122,101,110,73,109, - 112,111,114,116,101,114,46,108,111,97,100,95,109,111,100,117, - 108,101,99,2,0,0,0,0,0,0,0,0,0,0,0,2, - 0,0,0,3,0,0,0,67,0,0,0,115,10,0,0,0, - 116,0,160,1,124,1,161,1,83,0,41,1,122,45,82,101, - 116,117,114,110,32,116,104,101,32,99,111,100,101,32,111,98, - 106,101,99,116,32,102,111,114,32,116,104,101,32,102,114,111, - 122,101,110,32,109,111,100,117,108,101,46,41,2,114,56,0, - 0,0,114,179,0,0,0,114,172,0,0,0,114,10,0,0, - 0,114,10,0,0,0,114,11,0,0,0,114,173,0,0,0, - 70,3,0,0,115,2,0,0,0,0,4,122,23,70,114,111, - 122,101,110,73,109,112,111,114,116,101,114,46,103,101,116,95, - 99,111,100,101,99,2,0,0,0,0,0,0,0,0,0,0, - 0,2,0,0,0,1,0,0,0,67,0,0,0,115,4,0, - 0,0,100,1,83,0,41,2,122,54,82,101,116,117,114,110, - 32,78,111,110,101,32,97,115,32,102,114,111,122,101,110,32, - 109,111,100,117,108,101,115,32,100,111,32,110,111,116,32,104, - 97,118,101,32,115,111,117,114,99,101,32,99,111,100,101,46, - 78,114,10,0,0,0,114,172,0,0,0,114,10,0,0,0, - 114,10,0,0,0,114,11,0,0,0,114,174,0,0,0,76, - 3,0,0,115,2,0,0,0,0,4,122,25,70,114,111,122, - 101,110,73,109,112,111,114,116,101,114,46,103,101,116,95,115, - 111,117,114,99,101,99,2,0,0,0,0,0,0,0,0,0, - 0,0,2,0,0,0,3,0,0,0,67,0,0,0,115,10, - 0,0,0,116,0,160,1,124,1,161,1,83,0,41,1,122, - 46,82,101,116,117,114,110,32,84,114,117,101,32,105,102,32, - 116,104,101,32,102,114,111,122,101,110,32,109,111,100,117,108, - 101,32,105,115,32,97,32,112,97,99,107,97,103,101,46,41, - 2,114,56,0,0,0,90,17,105,115,95,102,114,111,122,101, - 110,95,112,97,99,107,97,103,101,114,172,0,0,0,114,10, - 0,0,0,114,10,0,0,0,114,11,0,0,0,114,117,0, - 0,0,82,3,0,0,115,2,0,0,0,0,4,122,25,70, - 114,111,122,101,110,73,109,112,111,114,116,101,114,46,105,115, - 95,112,97,99,107,97,103,101,41,2,78,78,41,1,78,41, - 17,114,1,0,0,0,114,0,0,0,0,114,2,0,0,0, - 114,3,0,0,0,114,142,0,0,0,114,175,0,0,0,114, - 99,0,0,0,114,176,0,0,0,114,170,0,0,0,114,171, - 0,0,0,114,153,0,0,0,114,154,0,0,0,114,159,0, - 0,0,114,90,0,0,0,114,173,0,0,0,114,174,0,0, - 0,114,117,0,0,0,114,10,0,0,0,114,10,0,0,0, - 114,10,0,0,0,114,11,0,0,0,114,177,0,0,0,13, - 3,0,0,115,46,0,0,0,8,2,4,7,4,2,2,1, - 10,8,2,1,12,6,2,1,12,8,2,1,10,3,2,1, - 10,7,2,1,10,8,2,1,2,1,12,4,2,1,2,1, - 12,4,2,1,2,1,114,177,0,0,0,99,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0, - 64,0,0,0,115,32,0,0,0,101,0,90,1,100,0,90, - 2,100,1,90,3,100,2,100,3,132,0,90,4,100,4,100, - 5,132,0,90,5,100,6,83,0,41,7,218,18,95,73,109, - 112,111,114,116,76,111,99,107,67,111,110,116,101,120,116,122, - 36,67,111,110,116,101,120,116,32,109,97,110,97,103,101,114, - 32,102,111,114,32,116,104,101,32,105,109,112,111,114,116,32, - 108,111,99,107,46,99,1,0,0,0,0,0,0,0,0,0, - 0,0,1,0,0,0,2,0,0,0,67,0,0,0,115,12, - 0,0,0,116,0,160,1,161,0,1,0,100,1,83,0,41, - 2,122,24,65,99,113,117,105,114,101,32,116,104,101,32,105, - 109,112,111,114,116,32,108,111,99,107,46,78,41,2,114,56, - 0,0,0,114,57,0,0,0,114,46,0,0,0,114,10,0, - 0,0,114,10,0,0,0,114,11,0,0,0,114,53,0,0, - 0,95,3,0,0,115,2,0,0,0,0,2,122,28,95,73, - 109,112,111,114,116,76,111,99,107,67,111,110,116,101,120,116, - 46,95,95,101,110,116,101,114,95,95,99,4,0,0,0,0, - 0,0,0,0,0,0,0,4,0,0,0,2,0,0,0,67, - 0,0,0,115,12,0,0,0,116,0,160,1,161,0,1,0, - 100,1,83,0,41,2,122,60,82,101,108,101,97,115,101,32, - 116,104,101,32,105,109,112,111,114,116,32,108,111,99,107,32, - 114,101,103,97,114,100,108,101,115,115,32,111,102,32,97,110, - 121,32,114,97,105,115,101,100,32,101,120,99,101,112,116,105, - 111,110,115,46,78,41,2,114,56,0,0,0,114,58,0,0, - 0,41,4,114,30,0,0,0,218,8,101,120,99,95,116,121, - 112,101,218,9,101,120,99,95,118,97,108,117,101,218,13,101, - 120,99,95,116,114,97,99,101,98,97,99,107,114,10,0,0, - 0,114,10,0,0,0,114,11,0,0,0,114,55,0,0,0, - 99,3,0,0,115,2,0,0,0,0,2,122,27,95,73,109, - 112,111,114,116,76,111,99,107,67,111,110,116,101,120,116,46, - 95,95,101,120,105,116,95,95,78,41,6,114,1,0,0,0, - 114,0,0,0,0,114,2,0,0,0,114,3,0,0,0,114, - 53,0,0,0,114,55,0,0,0,114,10,0,0,0,114,10, - 0,0,0,114,10,0,0,0,114,11,0,0,0,114,182,0, - 0,0,91,3,0,0,115,6,0,0,0,8,2,4,2,8, - 4,114,182,0,0,0,99,3,0,0,0,0,0,0,0,0, - 0,0,0,5,0,0,0,5,0,0,0,67,0,0,0,115, - 66,0,0,0,124,1,160,0,100,1,124,2,100,2,24,0, - 161,2,125,3,116,1,124,3,131,1,124,2,107,0,114,36, - 116,2,100,3,131,1,130,1,124,3,100,4,25,0,125,4, - 124,0,114,62,124,4,155,0,100,1,124,0,155,0,157,3, - 83,0,124,4,83,0,41,5,122,50,82,101,115,111,108,118, - 101,32,97,32,114,101,108,97,116,105,118,101,32,109,111,100, - 117,108,101,32,110,97,109,101,32,116,111,32,97,110,32,97, - 98,115,111,108,117,116,101,32,111,110,101,46,114,132,0,0, - 0,114,37,0,0,0,122,50,97,116,116,101,109,112,116,101, - 100,32,114,101,108,97,116,105,118,101,32,105,109,112,111,114, - 116,32,98,101,121,111,110,100,32,116,111,112,45,108,101,118, - 101,108,32,112,97,99,107,97,103,101,114,22,0,0,0,41, - 3,218,6,114,115,112,108,105,116,218,3,108,101,110,114,79, - 0,0,0,41,5,114,17,0,0,0,218,7,112,97,99,107, - 97,103,101,218,5,108,101,118,101,108,90,4,98,105,116,115, - 90,4,98,97,115,101,114,10,0,0,0,114,10,0,0,0, - 114,11,0,0,0,218,13,95,114,101,115,111,108,118,101,95, - 110,97,109,101,104,3,0,0,115,10,0,0,0,0,2,16, - 1,12,1,8,1,8,1,114,190,0,0,0,99,3,0,0, - 0,0,0,0,0,0,0,0,0,4,0,0,0,4,0,0, - 0,67,0,0,0,115,34,0,0,0,124,0,160,0,124,1, - 124,2,161,2,125,3,124,3,100,0,107,8,114,24,100,0, - 83,0,116,1,124,1,124,3,131,2,83,0,114,13,0,0, - 0,41,2,114,171,0,0,0,114,91,0,0,0,41,4,218, - 6,102,105,110,100,101,114,114,17,0,0,0,114,168,0,0, - 0,114,111,0,0,0,114,10,0,0,0,114,10,0,0,0, - 114,11,0,0,0,218,17,95,102,105,110,100,95,115,112,101, - 99,95,108,101,103,97,99,121,113,3,0,0,115,8,0,0, - 0,0,3,12,1,8,1,4,1,114,192,0,0,0,99,3, - 0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,10, - 0,0,0,67,0,0,0,115,12,1,0,0,116,0,106,1, - 125,3,124,3,100,1,107,8,114,22,116,2,100,2,131,1, - 130,1,124,3,115,38,116,3,160,4,100,3,116,5,161,2, - 1,0,124,0,116,0,106,6,107,6,125,4,124,3,68,0, - 93,210,125,5,116,7,131,0,143,84,1,0,122,10,124,5, - 106,8,125,6,87,0,110,54,4,0,116,9,107,10,114,128, - 1,0,1,0,1,0,116,10,124,5,124,0,124,1,131,3, - 125,7,124,7,100,1,107,8,114,124,89,0,87,0,53,0, - 81,0,82,0,163,0,113,52,89,0,110,14,88,0,124,6, - 124,0,124,1,124,2,131,3,125,7,87,0,53,0,81,0, - 82,0,88,0,124,7,100,1,107,9,114,52,124,4,144,0, - 115,254,124,0,116,0,106,6,107,6,144,0,114,254,116,0, - 106,6,124,0,25,0,125,8,122,10,124,8,106,11,125,9, - 87,0,110,28,4,0,116,9,107,10,114,226,1,0,1,0, - 1,0,124,7,6,0,89,0,2,0,1,0,83,0,88,0, - 124,9,100,1,107,8,114,244,124,7,2,0,1,0,83,0, - 124,9,2,0,1,0,83,0,113,52,124,7,2,0,1,0, - 83,0,113,52,100,1,83,0,41,4,122,21,70,105,110,100, - 32,97,32,109,111,100,117,108,101,39,115,32,115,112,101,99, - 46,78,122,53,115,121,115,46,109,101,116,97,95,112,97,116, - 104,32,105,115,32,78,111,110,101,44,32,80,121,116,104,111, - 110,32,105,115,32,108,105,107,101,108,121,32,115,104,117,116, - 116,105,110,103,32,100,111,119,110,122,22,115,121,115,46,109, - 101,116,97,95,112,97,116,104,32,105,115,32,101,109,112,116, - 121,41,12,114,15,0,0,0,218,9,109,101,116,97,95,112, - 97,116,104,114,79,0,0,0,218,9,95,119,97,114,110,105, - 110,103,115,218,4,119,97,114,110,218,13,73,109,112,111,114, - 116,87,97,114,110,105,110,103,114,92,0,0,0,114,182,0, - 0,0,114,170,0,0,0,114,108,0,0,0,114,192,0,0, - 0,114,107,0,0,0,41,10,114,17,0,0,0,114,168,0, - 0,0,114,169,0,0,0,114,193,0,0,0,90,9,105,115, - 95,114,101,108,111,97,100,114,191,0,0,0,114,170,0,0, - 0,114,95,0,0,0,114,96,0,0,0,114,107,0,0,0, - 114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,218, - 10,95,102,105,110,100,95,115,112,101,99,122,3,0,0,115, - 54,0,0,0,0,2,6,1,8,2,8,3,4,1,12,5, - 10,1,8,1,8,1,2,1,10,1,14,1,12,1,8,1, - 20,2,22,1,8,2,18,1,10,1,2,1,10,1,14,4, - 14,2,8,1,8,2,10,2,10,2,114,197,0,0,0,99, - 3,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0, - 4,0,0,0,67,0,0,0,115,108,0,0,0,116,0,124, - 0,116,1,131,2,115,28,116,2,100,1,116,3,124,0,131, - 1,155,0,157,2,131,1,130,1,124,2,100,2,107,0,114, - 44,116,4,100,3,131,1,130,1,124,2,100,2,107,4,114, - 84,116,0,124,1,116,1,131,2,115,72,116,2,100,4,131, - 1,130,1,110,12,124,1,115,84,116,5,100,5,131,1,130, - 1,124,0,115,104,124,2,100,2,107,2,114,104,116,4,100, - 6,131,1,130,1,100,7,83,0,41,8,122,28,86,101,114, - 105,102,121,32,97,114,103,117,109,101,110,116,115,32,97,114, - 101,32,34,115,97,110,101,34,46,122,29,109,111,100,117,108, - 101,32,110,97,109,101,32,109,117,115,116,32,98,101,32,115, - 116,114,44,32,110,111,116,32,114,22,0,0,0,122,18,108, - 101,118,101,108,32,109,117,115,116,32,98,101,32,62,61,32, - 48,122,31,95,95,112,97,99,107,97,103,101,95,95,32,110, - 111,116,32,115,101,116,32,116,111,32,97,32,115,116,114,105, - 110,103,122,54,97,116,116,101,109,112,116,101,100,32,114,101, - 108,97,116,105,118,101,32,105,109,112,111,114,116,32,119,105, - 116,104,32,110,111,32,107,110,111,119,110,32,112,97,114,101, - 110,116,32,112,97,99,107,97,103,101,122,17,69,109,112,116, - 121,32,109,111,100,117,108,101,32,110,97,109,101,78,41,6, - 218,10,105,115,105,110,115,116,97,110,99,101,218,3,115,116, - 114,218,9,84,121,112,101,69,114,114,111,114,114,14,0,0, - 0,218,10,86,97,108,117,101,69,114,114,111,114,114,79,0, - 0,0,169,3,114,17,0,0,0,114,188,0,0,0,114,189, - 0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,0, - 0,0,218,13,95,115,97,110,105,116,121,95,99,104,101,99, - 107,169,3,0,0,115,22,0,0,0,0,2,10,1,18,1, - 8,1,8,1,8,1,10,1,10,1,4,1,8,2,12,1, - 114,203,0,0,0,250,16,78,111,32,109,111,100,117,108,101, - 32,110,97,109,101,100,32,122,4,123,33,114,125,99,2,0, - 0,0,0,0,0,0,0,0,0,0,8,0,0,0,8,0, - 0,0,67,0,0,0,115,222,0,0,0,100,0,125,2,124, - 0,160,0,100,1,161,1,100,2,25,0,125,3,124,3,114, - 136,124,3,116,1,106,2,107,7,114,42,116,3,124,1,124, - 3,131,2,1,0,124,0,116,1,106,2,107,6,114,62,116, - 1,106,2,124,0,25,0,83,0,116,1,106,2,124,3,25, - 0,125,4,122,10,124,4,106,4,125,2,87,0,110,52,4, - 0,116,5,107,10,114,134,1,0,1,0,1,0,100,3,124, - 0,155,2,100,4,124,3,155,2,100,5,157,5,125,5,116, - 6,124,5,124,0,100,6,141,2,100,0,130,2,89,0,110, - 2,88,0,116,7,124,0,124,2,131,2,125,6,124,6,100, - 0,107,8,114,174,116,6,100,3,124,0,155,2,157,2,124, - 0,100,6,141,2,130,1,110,8,116,8,124,6,131,1,125, - 7,124,3,114,218,116,1,106,2,124,3,25,0,125,4,116, - 9,124,4,124,0,160,0,100,1,161,1,100,7,25,0,124, - 7,131,3,1,0,124,7,83,0,41,8,78,114,132,0,0, - 0,114,22,0,0,0,114,204,0,0,0,122,2,59,32,122, - 17,32,105,115,32,110,111,116,32,97,32,112,97,99,107,97, - 103,101,114,16,0,0,0,233,2,0,0,0,41,10,114,133, - 0,0,0,114,15,0,0,0,114,92,0,0,0,114,66,0, - 0,0,114,145,0,0,0,114,108,0,0,0,218,19,77,111, - 100,117,108,101,78,111,116,70,111,117,110,100,69,114,114,111, - 114,114,197,0,0,0,114,162,0,0,0,114,5,0,0,0, - 41,8,114,17,0,0,0,218,7,105,109,112,111,114,116,95, - 114,168,0,0,0,114,134,0,0,0,90,13,112,97,114,101, - 110,116,95,109,111,100,117,108,101,114,160,0,0,0,114,95, - 0,0,0,114,96,0,0,0,114,10,0,0,0,114,10,0, - 0,0,114,11,0,0,0,218,23,95,102,105,110,100,95,97, - 110,100,95,108,111,97,100,95,117,110,108,111,99,107,101,100, - 188,3,0,0,115,42,0,0,0,0,1,4,1,14,1,4, - 1,10,1,10,2,10,1,10,1,10,1,2,1,10,1,14, - 1,18,1,20,1,10,1,8,1,20,2,8,1,4,2,10, - 1,22,1,114,208,0,0,0,99,2,0,0,0,0,0,0, - 0,0,0,0,0,4,0,0,0,10,0,0,0,67,0,0, - 0,115,108,0,0,0,116,0,124,0,131,1,143,50,1,0, - 116,1,106,2,160,3,124,0,116,4,161,2,125,2,124,2, - 116,4,107,8,114,54,116,5,124,0,124,1,131,2,87,0, - 2,0,53,0,81,0,82,0,163,0,83,0,87,0,53,0, - 81,0,82,0,88,0,124,2,100,1,107,8,114,96,100,2, - 124,0,155,0,100,3,157,3,125,3,116,6,124,3,124,0, - 100,4,141,2,130,1,116,7,124,0,131,1,1,0,124,2, - 83,0,41,5,122,25,70,105,110,100,32,97,110,100,32,108, - 111,97,100,32,116,104,101,32,109,111,100,117,108,101,46,78, - 122,10,105,109,112,111,114,116,32,111,102,32,122,28,32,104, - 97,108,116,101,100,59,32,78,111,110,101,32,105,110,32,115, - 121,115,46,109,111,100,117,108,101,115,114,16,0,0,0,41, - 8,114,49,0,0,0,114,15,0,0,0,114,92,0,0,0, - 114,34,0,0,0,218,14,95,78,69,69,68,83,95,76,79, - 65,68,73,78,71,114,208,0,0,0,114,206,0,0,0,114, - 64,0,0,0,41,4,114,17,0,0,0,114,207,0,0,0, - 114,96,0,0,0,114,75,0,0,0,114,10,0,0,0,114, - 10,0,0,0,114,11,0,0,0,218,14,95,102,105,110,100, - 95,97,110,100,95,108,111,97,100,218,3,0,0,115,18,0, - 0,0,0,2,10,1,14,1,8,1,32,2,8,1,12,2, - 12,2,8,1,114,210,0,0,0,114,22,0,0,0,99,3, - 0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,4, - 0,0,0,67,0,0,0,115,42,0,0,0,116,0,124,0, - 124,1,124,2,131,3,1,0,124,2,100,1,107,4,114,32, - 116,1,124,0,124,1,124,2,131,3,125,0,116,2,124,0, - 116,3,131,2,83,0,41,2,97,50,1,0,0,73,109,112, - 111,114,116,32,97,110,100,32,114,101,116,117,114,110,32,116, - 104,101,32,109,111,100,117,108,101,32,98,97,115,101,100,32, - 111,110,32,105,116,115,32,110,97,109,101,44,32,116,104,101, - 32,112,97,99,107,97,103,101,32,116,104,101,32,99,97,108, - 108,32,105,115,10,32,32,32,32,98,101,105,110,103,32,109, - 97,100,101,32,102,114,111,109,44,32,97,110,100,32,116,104, - 101,32,108,101,118,101,108,32,97,100,106,117,115,116,109,101, - 110,116,46,10,10,32,32,32,32,84,104,105,115,32,102,117, - 110,99,116,105,111,110,32,114,101,112,114,101,115,101,110,116, - 115,32,116,104,101,32,103,114,101,97,116,101,115,116,32,99, - 111,109,109,111,110,32,100,101,110,111,109,105,110,97,116,111, - 114,32,111,102,32,102,117,110,99,116,105,111,110,97,108,105, - 116,121,10,32,32,32,32,98,101,116,119,101,101,110,32,105, - 109,112,111,114,116,95,109,111,100,117,108,101,32,97,110,100, - 32,95,95,105,109,112,111,114,116,95,95,46,32,84,104,105, - 115,32,105,110,99,108,117,100,101,115,32,115,101,116,116,105, - 110,103,32,95,95,112,97,99,107,97,103,101,95,95,32,105, - 102,10,32,32,32,32,116,104,101,32,108,111,97,100,101,114, - 32,100,105,100,32,110,111,116,46,10,10,32,32,32,32,114, - 22,0,0,0,41,4,114,203,0,0,0,114,190,0,0,0, - 114,210,0,0,0,218,11,95,103,99,100,95,105,109,112,111, - 114,116,114,202,0,0,0,114,10,0,0,0,114,10,0,0, - 0,114,11,0,0,0,114,211,0,0,0,234,3,0,0,115, - 8,0,0,0,0,9,12,1,8,1,12,1,114,211,0,0, - 0,169,1,218,9,114,101,99,117,114,115,105,118,101,99,3, - 0,0,0,0,0,0,0,1,0,0,0,8,0,0,0,11, - 0,0,0,67,0,0,0,115,228,0,0,0,124,1,68,0, - 93,218,125,4,116,0,124,4,116,1,131,2,115,66,124,3, - 114,34,124,0,106,2,100,1,23,0,125,5,110,4,100,2, - 125,5,116,3,100,3,124,5,155,0,100,4,116,4,124,4, - 131,1,106,2,155,0,157,4,131,1,130,1,113,4,124,4, - 100,5,107,2,114,108,124,3,115,222,116,5,124,0,100,6, - 131,2,114,222,116,6,124,0,124,0,106,7,124,2,100,7, - 100,8,141,4,1,0,113,4,116,5,124,0,124,4,131,2, - 115,4,124,0,106,2,155,0,100,9,124,4,155,0,157,3, - 125,6,122,14,116,8,124,2,124,6,131,2,1,0,87,0, - 113,4,4,0,116,9,107,10,114,220,1,0,125,7,1,0, - 122,42,124,7,106,10,124,6,107,2,114,202,116,11,106,12, - 160,13,124,6,116,14,161,2,100,10,107,9,114,202,87,0, - 89,0,162,8,113,4,130,0,87,0,53,0,100,10,125,7, - 126,7,88,0,89,0,113,4,88,0,113,4,124,0,83,0, - 41,11,122,238,70,105,103,117,114,101,32,111,117,116,32,119, - 104,97,116,32,95,95,105,109,112,111,114,116,95,95,32,115, - 104,111,117,108,100,32,114,101,116,117,114,110,46,10,10,32, - 32,32,32,84,104,101,32,105,109,112,111,114,116,95,32,112, - 97,114,97,109,101,116,101,114,32,105,115,32,97,32,99,97, - 108,108,97,98,108,101,32,119,104,105,99,104,32,116,97,107, - 101,115,32,116,104,101,32,110,97,109,101,32,111,102,32,109, - 111,100,117,108,101,32,116,111,10,32,32,32,32,105,109,112, - 111,114,116,46,32,73,116,32,105,115,32,114,101,113,117,105, - 114,101,100,32,116,111,32,100,101,99,111,117,112,108,101,32, - 116,104,101,32,102,117,110,99,116,105,111,110,32,102,114,111, - 109,32,97,115,115,117,109,105,110,103,32,105,109,112,111,114, - 116,108,105,98,39,115,10,32,32,32,32,105,109,112,111,114, - 116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110, - 32,105,115,32,100,101,115,105,114,101,100,46,10,10,32,32, - 32,32,122,8,46,95,95,97,108,108,95,95,122,13,96,96, - 102,114,111,109,32,108,105,115,116,39,39,122,8,73,116,101, - 109,32,105,110,32,122,18,32,109,117,115,116,32,98,101,32, - 115,116,114,44,32,110,111,116,32,250,1,42,218,7,95,95, - 97,108,108,95,95,84,114,212,0,0,0,114,132,0,0,0, - 78,41,15,114,198,0,0,0,114,199,0,0,0,114,1,0, - 0,0,114,200,0,0,0,114,14,0,0,0,114,4,0,0, - 0,218,16,95,104,97,110,100,108,101,95,102,114,111,109,108, - 105,115,116,114,215,0,0,0,114,66,0,0,0,114,206,0, - 0,0,114,17,0,0,0,114,15,0,0,0,114,92,0,0, - 0,114,34,0,0,0,114,209,0,0,0,41,8,114,96,0, - 0,0,218,8,102,114,111,109,108,105,115,116,114,207,0,0, - 0,114,213,0,0,0,218,1,120,90,5,119,104,101,114,101, - 90,9,102,114,111,109,95,110,97,109,101,90,3,101,120,99, - 114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,114, - 216,0,0,0,249,3,0,0,115,44,0,0,0,0,10,8, - 1,10,1,4,1,12,2,4,1,28,2,8,1,14,1,10, - 1,2,255,8,2,10,1,16,1,2,1,14,1,16,4,10, - 1,16,255,2,2,8,1,22,1,114,216,0,0,0,99,1, - 0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,6, - 0,0,0,67,0,0,0,115,146,0,0,0,124,0,160,0, - 100,1,161,1,125,1,124,0,160,0,100,2,161,1,125,2, - 124,1,100,3,107,9,114,82,124,2,100,3,107,9,114,78, - 124,1,124,2,106,1,107,3,114,78,116,2,106,3,100,4, - 124,1,155,2,100,5,124,2,106,1,155,2,100,6,157,5, - 116,4,100,7,100,8,141,3,1,0,124,1,83,0,124,2, - 100,3,107,9,114,96,124,2,106,1,83,0,116,2,106,3, - 100,9,116,4,100,7,100,8,141,3,1,0,124,0,100,10, - 25,0,125,1,100,11,124,0,107,7,114,142,124,1,160,5, - 100,12,161,1,100,13,25,0,125,1,124,1,83,0,41,14, - 122,167,67,97,108,99,117,108,97,116,101,32,119,104,97,116, - 32,95,95,112,97,99,107,97,103,101,95,95,32,115,104,111, - 117,108,100,32,98,101,46,10,10,32,32,32,32,95,95,112, - 97,99,107,97,103,101,95,95,32,105,115,32,110,111,116,32, - 103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101, - 32,100,101,102,105,110,101,100,32,111,114,32,99,111,117,108, - 100,32,98,101,32,115,101,116,32,116,111,32,78,111,110,101, - 10,32,32,32,32,116,111,32,114,101,112,114,101,115,101,110, - 116,32,116,104,97,116,32,105,116,115,32,112,114,111,112,101, - 114,32,118,97,108,117,101,32,105,115,32,117,110,107,110,111, - 119,110,46,10,10,32,32,32,32,114,149,0,0,0,114,107, - 0,0,0,78,122,32,95,95,112,97,99,107,97,103,101,95, - 95,32,33,61,32,95,95,115,112,101,99,95,95,46,112,97, - 114,101,110,116,32,40,122,4,32,33,61,32,114,122,0,0, - 0,233,3,0,0,0,41,1,90,10,115,116,97,99,107,108, - 101,118,101,108,122,89,99,97,110,39,116,32,114,101,115,111, - 108,118,101,32,112,97,99,107,97,103,101,32,102,114,111,109, - 32,95,95,115,112,101,99,95,95,32,111,114,32,95,95,112, - 97,99,107,97,103,101,95,95,44,32,102,97,108,108,105,110, - 103,32,98,97,99,107,32,111,110,32,95,95,110,97,109,101, - 95,95,32,97,110,100,32,95,95,112,97,116,104,95,95,114, - 1,0,0,0,114,145,0,0,0,114,132,0,0,0,114,22, - 0,0,0,41,6,114,34,0,0,0,114,134,0,0,0,114, - 194,0,0,0,114,195,0,0,0,114,196,0,0,0,114,133, - 0,0,0,41,3,218,7,103,108,111,98,97,108,115,114,188, - 0,0,0,114,95,0,0,0,114,10,0,0,0,114,10,0, - 0,0,114,11,0,0,0,218,17,95,99,97,108,99,95,95, - 95,112,97,99,107,97,103,101,95,95,30,4,0,0,115,38, - 0,0,0,0,7,10,1,10,1,8,1,18,1,22,2,2, - 0,2,254,6,3,4,1,8,1,6,2,6,2,2,0,2, - 254,6,3,8,1,8,1,14,1,114,221,0,0,0,114,10, - 0,0,0,99,5,0,0,0,0,0,0,0,0,0,0,0, - 9,0,0,0,5,0,0,0,67,0,0,0,115,180,0,0, - 0,124,4,100,1,107,2,114,18,116,0,124,0,131,1,125, - 5,110,36,124,1,100,2,107,9,114,30,124,1,110,2,105, - 0,125,6,116,1,124,6,131,1,125,7,116,0,124,0,124, - 7,124,4,131,3,125,5,124,3,115,150,124,4,100,1,107, - 2,114,84,116,0,124,0,160,2,100,3,161,1,100,1,25, - 0,131,1,83,0,124,0,115,92,124,5,83,0,116,3,124, - 0,131,1,116,3,124,0,160,2,100,3,161,1,100,1,25, - 0,131,1,24,0,125,8,116,4,106,5,124,5,106,6,100, - 2,116,3,124,5,106,6,131,1,124,8,24,0,133,2,25, - 0,25,0,83,0,110,26,116,7,124,5,100,4,131,2,114, - 172,116,8,124,5,124,3,116,0,131,3,83,0,124,5,83, - 0,100,2,83,0,41,5,97,215,1,0,0,73,109,112,111, - 114,116,32,97,32,109,111,100,117,108,101,46,10,10,32,32, - 32,32,84,104,101,32,39,103,108,111,98,97,108,115,39,32, - 97,114,103,117,109,101,110,116,32,105,115,32,117,115,101,100, - 32,116,111,32,105,110,102,101,114,32,119,104,101,114,101,32, - 116,104,101,32,105,109,112,111,114,116,32,105,115,32,111,99, - 99,117,114,114,105,110,103,32,102,114,111,109,10,32,32,32, - 32,116,111,32,104,97,110,100,108,101,32,114,101,108,97,116, - 105,118,101,32,105,109,112,111,114,116,115,46,32,84,104,101, - 32,39,108,111,99,97,108,115,39,32,97,114,103,117,109,101, - 110,116,32,105,115,32,105,103,110,111,114,101,100,46,32,84, - 104,101,10,32,32,32,32,39,102,114,111,109,108,105,115,116, - 39,32,97,114,103,117,109,101,110,116,32,115,112,101,99,105, - 102,105,101,115,32,119,104,97,116,32,115,104,111,117,108,100, - 32,101,120,105,115,116,32,97,115,32,97,116,116,114,105,98, - 117,116,101,115,32,111,110,32,116,104,101,32,109,111,100,117, - 108,101,10,32,32,32,32,98,101,105,110,103,32,105,109,112, - 111,114,116,101,100,32,40,101,46,103,46,32,96,96,102,114, - 111,109,32,109,111,100,117,108,101,32,105,109,112,111,114,116, - 32,60,102,114,111,109,108,105,115,116,62,96,96,41,46,32, - 32,84,104,101,32,39,108,101,118,101,108,39,10,32,32,32, - 32,97,114,103,117,109,101,110,116,32,114,101,112,114,101,115, - 101,110,116,115,32,116,104,101,32,112,97,99,107,97,103,101, - 32,108,111,99,97,116,105,111,110,32,116,111,32,105,109,112, - 111,114,116,32,102,114,111,109,32,105,110,32,97,32,114,101, - 108,97,116,105,118,101,10,32,32,32,32,105,109,112,111,114, - 116,32,40,101,46,103,46,32,96,96,102,114,111,109,32,46, - 46,112,107,103,32,105,109,112,111,114,116,32,109,111,100,96, - 96,32,119,111,117,108,100,32,104,97,118,101,32,97,32,39, - 108,101,118,101,108,39,32,111,102,32,50,41,46,10,10,32, - 32,32,32,114,22,0,0,0,78,114,132,0,0,0,114,145, - 0,0,0,41,9,114,211,0,0,0,114,221,0,0,0,218, - 9,112,97,114,116,105,116,105,111,110,114,187,0,0,0,114, - 15,0,0,0,114,92,0,0,0,114,1,0,0,0,114,4, - 0,0,0,114,216,0,0,0,41,9,114,17,0,0,0,114, - 220,0,0,0,218,6,108,111,99,97,108,115,114,217,0,0, - 0,114,189,0,0,0,114,96,0,0,0,90,8,103,108,111, - 98,97,108,115,95,114,188,0,0,0,90,7,99,117,116,95, - 111,102,102,114,10,0,0,0,114,10,0,0,0,114,11,0, - 0,0,218,10,95,95,105,109,112,111,114,116,95,95,57,4, - 0,0,115,30,0,0,0,0,11,8,1,10,2,16,1,8, - 1,12,1,4,3,8,1,18,1,4,1,4,4,26,3,32, - 1,10,1,12,2,114,224,0,0,0,99,1,0,0,0,0, - 0,0,0,0,0,0,0,2,0,0,0,3,0,0,0,67, - 0,0,0,115,38,0,0,0,116,0,160,1,124,0,161,1, - 125,1,124,1,100,0,107,8,114,30,116,2,100,1,124,0, - 23,0,131,1,130,1,116,3,124,1,131,1,83,0,41,2, - 78,122,25,110,111,32,98,117,105,108,116,45,105,110,32,109, - 111,100,117,108,101,32,110,97,109,101,100,32,41,4,114,163, - 0,0,0,114,170,0,0,0,114,79,0,0,0,114,162,0, - 0,0,41,2,114,17,0,0,0,114,95,0,0,0,114,10, - 0,0,0,114,10,0,0,0,114,11,0,0,0,218,18,95, - 98,117,105,108,116,105,110,95,102,114,111,109,95,110,97,109, - 101,94,4,0,0,115,8,0,0,0,0,1,10,1,8,1, - 12,1,114,225,0,0,0,99,2,0,0,0,0,0,0,0, - 0,0,0,0,10,0,0,0,5,0,0,0,67,0,0,0, - 115,166,0,0,0,124,1,97,0,124,0,97,1,116,2,116, - 1,131,1,125,2,116,1,106,3,160,4,161,0,68,0,93, - 72,92,2,125,3,125,4,116,5,124,4,124,2,131,2,114, - 26,124,3,116,1,106,6,107,6,114,60,116,7,125,5,110, - 18,116,0,160,8,124,3,161,1,114,26,116,9,125,5,110, - 2,113,26,116,10,124,4,124,5,131,2,125,6,116,11,124, - 6,124,4,131,2,1,0,113,26,116,1,106,3,116,12,25, - 0,125,7,100,1,68,0,93,46,125,8,124,8,116,1,106, - 3,107,7,114,138,116,13,124,8,131,1,125,9,110,10,116, - 1,106,3,124,8,25,0,125,9,116,14,124,7,124,8,124, - 9,131,3,1,0,113,114,100,2,83,0,41,3,122,250,83, - 101,116,117,112,32,105,109,112,111,114,116,108,105,98,32,98, - 121,32,105,109,112,111,114,116,105,110,103,32,110,101,101,100, - 101,100,32,98,117,105,108,116,45,105,110,32,109,111,100,117, - 108,101,115,32,97,110,100,32,105,110,106,101,99,116,105,110, - 103,32,116,104,101,109,10,32,32,32,32,105,110,116,111,32, - 116,104,101,32,103,108,111,98,97,108,32,110,97,109,101,115, - 112,97,99,101,46,10,10,32,32,32,32,65,115,32,115,121, - 115,32,105,115,32,110,101,101,100,101,100,32,102,111,114,32, - 115,121,115,46,109,111,100,117,108,101,115,32,97,99,99,101, - 115,115,32,97,110,100,32,95,105,109,112,32,105,115,32,110, - 101,101,100,101,100,32,116,111,32,108,111,97,100,32,98,117, - 105,108,116,45,105,110,10,32,32,32,32,109,111,100,117,108, - 101,115,44,32,116,104,111,115,101,32,116,119,111,32,109,111, - 100,117,108,101,115,32,109,117,115,116,32,98,101,32,101,120, - 112,108,105,99,105,116,108,121,32,112,97,115,115,101,100,32, - 105,110,46,10,10,32,32,32,32,41,3,114,23,0,0,0, - 114,194,0,0,0,114,63,0,0,0,78,41,15,114,56,0, - 0,0,114,15,0,0,0,114,14,0,0,0,114,92,0,0, - 0,218,5,105,116,101,109,115,114,198,0,0,0,114,78,0, - 0,0,114,163,0,0,0,114,88,0,0,0,114,177,0,0, - 0,114,146,0,0,0,114,152,0,0,0,114,1,0,0,0, - 114,225,0,0,0,114,5,0,0,0,41,10,218,10,115,121, - 115,95,109,111,100,117,108,101,218,11,95,105,109,112,95,109, - 111,100,117,108,101,90,11,109,111,100,117,108,101,95,116,121, - 112,101,114,17,0,0,0,114,96,0,0,0,114,111,0,0, - 0,114,95,0,0,0,90,11,115,101,108,102,95,109,111,100, - 117,108,101,90,12,98,117,105,108,116,105,110,95,110,97,109, - 101,90,14,98,117,105,108,116,105,110,95,109,111,100,117,108, - 101,114,10,0,0,0,114,10,0,0,0,114,11,0,0,0, - 218,6,95,115,101,116,117,112,101,4,0,0,115,36,0,0, - 0,0,9,4,1,4,3,8,1,18,1,10,1,10,1,6, - 1,10,1,6,2,2,1,10,1,12,3,10,1,8,1,10, - 1,10,2,10,1,114,229,0,0,0,99,2,0,0,0,0, - 0,0,0,0,0,0,0,2,0,0,0,3,0,0,0,67, - 0,0,0,115,38,0,0,0,116,0,124,0,124,1,131,2, - 1,0,116,1,106,2,160,3,116,4,161,1,1,0,116,1, - 106,2,160,3,116,5,161,1,1,0,100,1,83,0,41,2, - 122,48,73,110,115,116,97,108,108,32,105,109,112,111,114,116, - 101,114,115,32,102,111,114,32,98,117,105,108,116,105,110,32, - 97,110,100,32,102,114,111,122,101,110,32,109,111,100,117,108, - 101,115,78,41,6,114,229,0,0,0,114,15,0,0,0,114, - 193,0,0,0,114,123,0,0,0,114,163,0,0,0,114,177, - 0,0,0,41,2,114,227,0,0,0,114,228,0,0,0,114, - 10,0,0,0,114,10,0,0,0,114,11,0,0,0,218,8, - 95,105,110,115,116,97,108,108,136,4,0,0,115,6,0,0, - 0,0,2,10,2,12,1,114,230,0,0,0,99,0,0,0, - 0,0,0,0,0,0,0,0,0,1,0,0,0,4,0,0, - 0,67,0,0,0,115,32,0,0,0,100,1,100,2,108,0, - 125,0,124,0,97,1,124,0,160,2,116,3,106,4,116,5, - 25,0,161,1,1,0,100,2,83,0,41,3,122,57,73,110, - 115,116,97,108,108,32,105,109,112,111,114,116,101,114,115,32, - 116,104,97,116,32,114,101,113,117,105,114,101,32,101,120,116, - 101,114,110,97,108,32,102,105,108,101,115,121,115,116,101,109, - 32,97,99,99,101,115,115,114,22,0,0,0,78,41,6,218, - 26,95,102,114,111,122,101,110,95,105,109,112,111,114,116,108, - 105,98,95,101,120,116,101,114,110,97,108,114,130,0,0,0, - 114,230,0,0,0,114,15,0,0,0,114,92,0,0,0,114, - 1,0,0,0,41,1,114,231,0,0,0,114,10,0,0,0, - 114,10,0,0,0,114,11,0,0,0,218,27,95,105,110,115, - 116,97,108,108,95,101,120,116,101,114,110,97,108,95,105,109, - 112,111,114,116,101,114,115,144,4,0,0,115,6,0,0,0, - 0,3,8,1,4,1,114,232,0,0,0,41,2,78,78,41, - 1,78,41,2,78,114,22,0,0,0,41,4,78,78,114,10, - 0,0,0,114,22,0,0,0,41,50,114,3,0,0,0,114, - 130,0,0,0,114,12,0,0,0,114,18,0,0,0,114,59, - 0,0,0,114,33,0,0,0,114,42,0,0,0,114,19,0, - 0,0,114,20,0,0,0,114,48,0,0,0,114,49,0,0, - 0,114,52,0,0,0,114,64,0,0,0,114,66,0,0,0, - 114,76,0,0,0,114,86,0,0,0,114,90,0,0,0,114, - 97,0,0,0,114,113,0,0,0,114,114,0,0,0,114,91, - 0,0,0,114,146,0,0,0,114,152,0,0,0,114,156,0, - 0,0,114,109,0,0,0,114,93,0,0,0,114,161,0,0, - 0,114,162,0,0,0,114,94,0,0,0,114,163,0,0,0, - 114,177,0,0,0,114,182,0,0,0,114,190,0,0,0,114, - 192,0,0,0,114,197,0,0,0,114,203,0,0,0,90,15, - 95,69,82,82,95,77,83,71,95,80,82,69,70,73,88,90, - 8,95,69,82,82,95,77,83,71,114,208,0,0,0,218,6, - 111,98,106,101,99,116,114,209,0,0,0,114,210,0,0,0, - 114,211,0,0,0,114,216,0,0,0,114,221,0,0,0,114, - 224,0,0,0,114,225,0,0,0,114,229,0,0,0,114,230, - 0,0,0,114,232,0,0,0,114,10,0,0,0,114,10,0, - 0,0,114,10,0,0,0,114,11,0,0,0,218,8,60,109, - 111,100,117,108,101,62,1,0,0,0,115,94,0,0,0,4, - 24,4,2,8,8,8,8,4,2,4,3,16,4,14,68,14, - 21,14,16,8,37,8,17,8,11,14,8,8,11,8,12,8, - 16,8,36,14,100,16,26,10,45,14,72,8,17,8,17,8, - 30,8,37,8,42,8,15,14,75,14,78,14,13,8,9,8, - 9,10,47,8,16,4,1,8,2,8,27,6,3,8,16,10, - 15,14,37,8,27,10,37,8,7,8,35,8,8, -}; diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index d82fb967297c..5924ab7860d8 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -328,7 +328,6 @@ def clean_lines(text): _abs('Python/frozen_modules/*.h'): (20_000, 500), _abs('Python/opcode_targets.h'): (10_000, 500), _abs('Python/stdlib_module_names.h'): (5_000, 500), - _abs('Python/importlib.h'): (200_000, 5000), # These large files are currently ignored (see above). _abs('Modules/_ssl_data.h'): (80_000, 10_000), diff --git a/configure b/configure index 9e99352f589f..4ae8258438e6 100755 --- a/configure +++ b/configure @@ -3104,7 +3104,6 @@ if test "$srcdir" != . -a "$srcdir" != "$(pwd)"; then # resources get picked up before their $srcdir counterparts. # Objects/ -> typeslots.inc # Include/ -> Python.h - # Python/ -> importlib.h # (A side effect of this is that these resources will automatically be # regenerated when building out-of-tree, regardless of whether or not # the $srcdir counterpart is up-to-date. This is an acceptable trade diff --git a/configure.ac b/configure.ac index 31b7a2157a2b..4d9eb46f5ce7 100644 --- a/configure.ac +++ b/configure.ac @@ -97,7 +97,6 @@ if test "$srcdir" != . -a "$srcdir" != "$(pwd)"; then # resources get picked up before their $srcdir counterparts. # Objects/ -> typeslots.inc # Include/ -> Python.h - # Python/ -> importlib.h # (A side effect of this is that these resources will automatically be # regenerated when building out-of-tree, regardless of whether or not # the $srcdir counterpart is up-to-date. This is an acceptable trade From webhook-mailer at python.org Wed Apr 12 16:11:57 2023 From: webhook-mailer at python.org (zooba) Date: Wed, 12 Apr 2023 20:11:57 -0000 Subject: [Python-checkins] gh-103088: Fix virtual environment activate script not working in Cygwin (GH-103470) Message-ID: https://github.com/python/cpython/commit/2b6e8777672da03f5d5cd12366e8378e47c550da commit: 2b6e8777672da03f5d5cd12366e8378e47c550da branch: main author: Stanislav Syekirin committer: zooba date: 2023-04-12T21:11:50+01:00 summary: gh-103088: Fix virtual environment activate script not working in Cygwin (GH-103470) files: A Misc/NEWS.d/next/Windows/2023-04-12-10-49-21.gh-issue-103088.Yjj-qJ.rst M .gitattributes M Lib/test/test_venv.py diff --git a/.gitattributes b/.gitattributes index 132891824001..cb1cf8bcc7c8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -32,6 +32,9 @@ Lib/test/test_importlib/resources/data01/* noeol Lib/test/test_importlib/resources/namespacedata01/* noeol Lib/test/xmltestdata/* noeol +# Shell scripts should have LF even on Windows because of Cygwin +Lib/venv/scripts/common/activate text eol=lf + # CRLF files [attr]dos text eol=crlf diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index 4e18dfc23c40..23328431a7aa 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -611,6 +611,21 @@ def test_zippath_from_non_installed_posix(self): out, err = check_output(cmd) self.assertTrue(zip_landmark.encode() in out) + def test_activate_shell_script_has_no_dos_newlines(self): + """ + Test that the `activate` shell script contains no CR LF. + This is relevant for Cygwin, as the Windows build might have + converted line endings accidentally. + """ + venv_dir = pathlib.Path(self.env_dir) + rmtree(venv_dir) + [[scripts_dir], *_] = self.ENV_SUBDIRS + script_path = venv_dir / scripts_dir / "activate" + venv.create(venv_dir) + with open(script_path, 'rb') as script: + for line in script: + self.assertFalse(line.endswith(b'\r\n'), line) + @requireVenvCreate class EnsurePipTest(BaseTest): """Test venv module installation of pip.""" diff --git a/Misc/NEWS.d/next/Windows/2023-04-12-10-49-21.gh-issue-103088.Yjj-qJ.rst b/Misc/NEWS.d/next/Windows/2023-04-12-10-49-21.gh-issue-103088.Yjj-qJ.rst new file mode 100644 index 000000000000..1fee99da2403 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-04-12-10-49-21.gh-issue-103088.Yjj-qJ.rst @@ -0,0 +1 @@ +Fix virtual environment :file:`activate` script having incorrect line endings for Cygwin. From webhook-mailer at python.org Wed Apr 12 18:32:39 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 12 Apr 2023 22:32:39 -0000 Subject: [Python-checkins] gh-67230: add quoting rules to csv module (GH-29469) Message-ID: https://github.com/python/cpython/commit/330a942b6303c889d0f42f23d5ae2b42af92ecc4 commit: 330a942b6303c889d0f42f23d5ae2b42af92ecc4 branch: main author: Skip Montanaro committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-12T15:32:30-07:00 summary: gh-67230: add quoting rules to csv module (GH-29469) Add two quoting styles for csv dialects. They will help to work with certain databases in particular. Automerge-Triggered-By: GH:merwok files: A Misc/NEWS.d/next/Library/2021-11-07-15-31-25.bpo-23041.564i32.rst M Doc/library/csv.rst M Lib/csv.py M Lib/test/test_csv.py M Modules/_csv.c diff --git a/Doc/library/csv.rst b/Doc/library/csv.rst index f1776554d8b9..64baa69be4af 100644 --- a/Doc/library/csv.rst +++ b/Doc/library/csv.rst @@ -327,7 +327,7 @@ The :mod:`csv` module defines the following constants: Instructs :class:`writer` objects to quote all non-numeric fields. - Instructs the reader to convert all non-quoted fields to type *float*. + Instructs :class:`reader` objects to convert all non-quoted fields to type *float*. .. data:: QUOTE_NONE @@ -337,7 +337,25 @@ The :mod:`csv` module defines the following constants: character. If *escapechar* is not set, the writer will raise :exc:`Error` if any characters that require escaping are encountered. - Instructs :class:`reader` to perform no special processing of quote characters. + Instructs :class:`reader` objects to perform no special processing of quote characters. + +.. data:: QUOTE_NOTNULL + + Instructs :class:`writer` objects to quote all fields which are not + ``None``. This is similar to :data:`QUOTE_ALL`, except that if a + field value is ``None`` an empty (unquoted) string is written. + + Instructs :class:`reader` objects to interpret an empty (unquoted) field as None and + to otherwise behave as :data:`QUOTE_ALL`. + +.. data:: QUOTE_STRINGS + + Instructs :class:`writer` objects to always place quotes around fields + which are strings. This is similar to :data:`QUOTE_NONNUMERIC`, except that if a + field value is ``None`` an empty (unquoted) string is written. + + Instructs :class:`reader` objects to interpret an empty (unquoted) string as ``None`` and + to otherwise behave as :data:`QUOTE_NONNUMERIC`. The :mod:`csv` module defines the following exception: diff --git a/Lib/csv.py b/Lib/csv.py index 4ef8be45ca9e..77f30c8d2b1f 100644 --- a/Lib/csv.py +++ b/Lib/csv.py @@ -9,12 +9,14 @@ unregister_dialect, get_dialect, list_dialects, \ field_size_limit, \ QUOTE_MINIMAL, QUOTE_ALL, QUOTE_NONNUMERIC, QUOTE_NONE, \ + QUOTE_STRINGS, QUOTE_NOTNULL, \ __doc__ from _csv import Dialect as _Dialect from io import StringIO __all__ = ["QUOTE_MINIMAL", "QUOTE_ALL", "QUOTE_NONNUMERIC", "QUOTE_NONE", + "QUOTE_STRINGS", "QUOTE_NOTNULL", "Error", "Dialect", "__doc__", "excel", "excel_tab", "field_size_limit", "reader", "writer", "register_dialect", "get_dialect", "list_dialects", "Sniffer", diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py index 8289ddb1c3a5..8fb97bc0c1a1 100644 --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -187,6 +187,10 @@ def test_write_quoting(self): quoting = csv.QUOTE_ALL) self._write_test(['a\nb',1], '"a\nb","1"', quoting = csv.QUOTE_ALL) + self._write_test(['a','',None,1], '"a","",,1', + quoting = csv.QUOTE_STRINGS) + self._write_test(['a','',None,1], '"a","",,"1"', + quoting = csv.QUOTE_NOTNULL) def test_write_escape(self): self._write_test(['a',1,'p,q'], 'a,1,"p,q"', diff --git a/Misc/NEWS.d/next/Library/2021-11-07-15-31-25.bpo-23041.564i32.rst b/Misc/NEWS.d/next/Library/2021-11-07-15-31-25.bpo-23041.564i32.rst new file mode 100644 index 000000000000..53c32d397b20 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-11-07-15-31-25.bpo-23041.564i32.rst @@ -0,0 +1,2 @@ +Add :data:`~csv.QUOTE_STRINGS` and :data:`~csv.QUOTE_NOTNULL` to the suite +of :mod:`csv` module quoting styles. diff --git a/Modules/_csv.c b/Modules/_csv.c index bd337084dbff..2217cc2ca7a7 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -82,7 +82,8 @@ typedef enum { } ParserState; typedef enum { - QUOTE_MINIMAL, QUOTE_ALL, QUOTE_NONNUMERIC, QUOTE_NONE + QUOTE_MINIMAL, QUOTE_ALL, QUOTE_NONNUMERIC, QUOTE_NONE, + QUOTE_STRINGS, QUOTE_NOTNULL } QuoteStyle; typedef struct { @@ -95,6 +96,8 @@ static const StyleDesc quote_styles[] = { { QUOTE_ALL, "QUOTE_ALL" }, { QUOTE_NONNUMERIC, "QUOTE_NONNUMERIC" }, { QUOTE_NONE, "QUOTE_NONE" }, + { QUOTE_STRINGS, "QUOTE_STRINGS" }, + { QUOTE_NOTNULL, "QUOTE_NOTNULL" }, { 0 } }; @@ -1264,6 +1267,12 @@ csv_writerow(WriterObj *self, PyObject *seq) case QUOTE_ALL: quoted = 1; break; + case QUOTE_STRINGS: + quoted = PyUnicode_Check(field); + break; + case QUOTE_NOTNULL: + quoted = field != Py_None; + break; default: quoted = 0; break; @@ -1659,6 +1668,11 @@ PyDoc_STRVAR(csv_module_doc, " csv.QUOTE_NONNUMERIC means that quotes are always placed around\n" " fields which do not parse as integers or floating point\n" " numbers.\n" +" csv.QUOTE_STRINGS means that quotes are always placed around\n" +" fields which are strings. Note that the Python value None\n" +" is not a string.\n" +" csv.QUOTE_NOTNULL means that quotes are only placed around fields\n" +" that are not the Python value None.\n" " csv.QUOTE_NONE means that quotes are never placed around fields.\n" " * escapechar - specifies a one-character string used to escape\n" " the delimiter when quoting is set to QUOTE_NONE.\n" From webhook-mailer at python.org Wed Apr 12 20:45:59 2023 From: webhook-mailer at python.org (merwok) Date: Thu, 13 Apr 2023 00:45:59 -0000 Subject: [Python-checkins] gh-67230: document new csv quoting modes in whatsnew (gh-103491) Message-ID: https://github.com/python/cpython/commit/fb38c1b52e77ffe6e8a02bfc01bd112dcd7e6d95 commit: fb38c1b52e77ffe6e8a02bfc01bd112dcd7e6d95 branch: main author: Skip Montanaro committer: merwok date: 2023-04-12T20:45:52-04:00 summary: gh-67230: document new csv quoting modes in whatsnew (gh-103491) files: M Doc/whatsnew/3.12.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index c7fc7d229cd7..4165b16ba764 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -253,6 +253,13 @@ asyncio * :func:`asyncio.wait` now accepts generators yielding tasks. (Contributed by Kumar Aditya in :gh:`78530`.) +csv +--- + +* Add :data:`~csv.QUOTE_NOTNULL` and :data:`~csv.QUOTE_STRINGS` flags to + provide finer grained control of ``None`` and empty strings by + :class:`~csv.reader` and :class:`~csv.writer` objects. + inspect ------- From webhook-mailer at python.org Thu Apr 13 00:17:43 2023 From: webhook-mailer at python.org (pradyunsg) Date: Thu, 13 Apr 2023 04:17:43 -0000 Subject: [Python-checkins] gh-95299: Rework test_cppext.py to not invoke setup.py directly (#103316) Message-ID: https://github.com/python/cpython/commit/9e677406ee6666b32d869ce68c826519ff877445 commit: 9e677406ee6666b32d869ce68c826519ff877445 branch: main author: Pradyun Gedam committer: pradyunsg date: 2023-04-12T23:17:36-05:00 summary: gh-95299: Rework test_cppext.py to not invoke setup.py directly (#103316) * gh-95299: Rework test_cppext.py to not invoke setup.py directly * Add tests/cppextdata data to `TESTSUBDIRS` * Revert "Add tests/cppextdata data to `TESTSUBDIRS`" This reverts commit 635492e53954fb0fc2a2875c8961bde99266c48d. * Revert "gh-95299: Rework test_cppext.py to not invoke setup.py directly" This reverts commit 41c5a667b5de7070bbde5780f1c124f96863c91d. * Build and install the extension in a temporary directory instead * Pull in wheels for setuptools and wheel for testing extension builds files: A Lib/test/setuptools-67.6.1-py3-none-any.whl A Lib/test/wheel-0.40.0-py3-none-any.whl M Lib/test/setup_testcppext.py M Lib/test/test_cppext.py diff --git a/Lib/test/setup_testcppext.py b/Lib/test/setup_testcppext.py index c6b68104d133..22fe750085fd 100644 --- a/Lib/test/setup_testcppext.py +++ b/Lib/test/setup_testcppext.py @@ -1,5 +1,6 @@ # gh-91321: Build a basic C++ test extension to check that the Python C API is # compatible with C++ and does not emit C++ compiler warnings. +import os import sys from test import support @@ -25,14 +26,8 @@ def main(): cppflags = list(CPPFLAGS) - if '-std=c++03' in sys.argv: - sys.argv.remove('-std=c++03') - std = 'c++03' - name = '_testcpp03ext' - else: - # Python currently targets C++11 - std = 'c++11' - name = '_testcpp11ext' + std = os.environ["CPYTHON_TEST_CPP_STD"] + name = os.environ["CPYTHON_TEST_EXT_NAME"] cppflags = [*CPPFLAGS, f'-std={std}'] diff --git a/Lib/test/setuptools-67.6.1-py3-none-any.whl b/Lib/test/setuptools-67.6.1-py3-none-any.whl new file mode 100644 index 000000000000..4b7ffd2e49e1 Binary files /dev/null and b/Lib/test/setuptools-67.6.1-py3-none-any.whl differ diff --git a/Lib/test/test_cppext.py b/Lib/test/test_cppext.py index 465894d24e7d..4fb62d87e860 100644 --- a/Lib/test/test_cppext.py +++ b/Lib/test/test_cppext.py @@ -1,6 +1,7 @@ # gh-91321: Build a basic C++ test extension to check that the Python C API is # compatible with C++ and does not emit C++ compiler warnings. import os.path +import shutil import sys import unittest import subprocess @@ -39,6 +40,10 @@ def check_build(self, std_cpp03, extension_name): self._check_build(std_cpp03, extension_name) def _check_build(self, std_cpp03, extension_name): + pkg_dir = 'pkg' + os.mkdir(pkg_dir) + shutil.copy(SETUP_TESTCPPEXT, os.path.join(pkg_dir, "setup.py")) + venv_dir = 'env' verbose = support.verbose @@ -59,11 +64,15 @@ def _check_build(self, std_cpp03, extension_name): python = os.path.join(venv_dir, 'bin', python_exe) def run_cmd(operation, cmd): + env = os.environ.copy() + env['CPYTHON_TEST_CPP_STD'] = 'c++03' if std_cpp03 else 'c++11' + env['CPYTHON_TEST_EXT_NAME'] = extension_name if verbose: print('Run:', ' '.join(cmd)) - subprocess.run(cmd, check=True) + subprocess.run(cmd, check=True, env=env) else: proc = subprocess.run(cmd, + env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) @@ -72,16 +81,16 @@ def run_cmd(operation, cmd): self.fail( f"{operation} failed with exit code {proc.returncode}") - # Build the C++ extension cmd = [python, '-X', 'dev', - SETUP_TESTCPPEXT, 'build_ext', '--verbose'] - if std_cpp03: - cmd.append('-std=c++03') - run_cmd('Build', cmd) + '-m', 'pip', 'install', + support.findfile('setuptools-67.6.1-py3-none-any.whl'), + support.findfile('wheel-0.40.0-py3-none-any.whl')] + run_cmd('Install build dependencies', cmd) - # Install the C++ extension + # Build and install the C++ extension cmd = [python, '-X', 'dev', - SETUP_TESTCPPEXT, 'install'] + '-m', 'pip', 'install', '--no-build-isolation', + os.path.abspath(pkg_dir)] run_cmd('Install', cmd) # Do a reference run. Until we test that running python diff --git a/Lib/test/wheel-0.40.0-py3-none-any.whl b/Lib/test/wheel-0.40.0-py3-none-any.whl new file mode 100644 index 000000000000..410132385bba Binary files /dev/null and b/Lib/test/wheel-0.40.0-py3-none-any.whl differ From webhook-mailer at python.org Thu Apr 13 00:47:06 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Thu, 13 Apr 2023 04:47:06 -0000 Subject: [Python-checkins] gh-103462: Ensure SelectorSocketTransport.writelines registers a writer when data is still pending (#103463) Message-ID: https://github.com/python/cpython/commit/19d2639d1e6478e2e251479d842bdfa2e8272396 commit: 19d2639d1e6478e2e251479d842bdfa2e8272396 branch: main author: Ali-Akber Saifee committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-04-13T10:16:52+05:30 summary: gh-103462: Ensure SelectorSocketTransport.writelines registers a writer when data is still pending (#103463) files: A Misc/NEWS.d/next/Library/2023-04-12-06-00-02.gh-issue-103462.w6yBlM.rst M Lib/asyncio/selector_events.py M Lib/test/test_asyncio/test_selector_events.py diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py index de5076a96218..3a697129e4c9 100644 --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -1176,6 +1176,9 @@ def writelines(self, list_of_data): return self._buffer.extend([memoryview(data) for data in list_of_data]) self._write_ready() + # If the entire buffer couldn't be written, register a write handler + if self._buffer: + self._loop._add_writer(self._sock_fd, self._write_ready) def can_write_eof(self): return True diff --git a/Lib/test/test_asyncio/test_selector_events.py b/Lib/test/test_asyncio/test_selector_events.py index 921c98a2702d..e41341fd26e1 100644 --- a/Lib/test/test_asyncio/test_selector_events.py +++ b/Lib/test/test_asyncio/test_selector_events.py @@ -747,6 +747,48 @@ def test_write_sendmsg_no_data(self): self.assertFalse(self.sock.sendmsg.called) self.assertEqual(list_to_buffer([b'data']), transport._buffer) + @unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg') + def test_writelines_sendmsg_full(self): + data = memoryview(b'data') + self.sock.sendmsg = mock.Mock() + self.sock.sendmsg.return_value = len(data) + + transport = self.socket_transport(sendmsg=True) + transport.writelines([data]) + self.assertTrue(self.sock.sendmsg.called) + self.assertFalse(self.loop.writers) + + @unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg') + def test_writelines_sendmsg_partial(self): + data = memoryview(b'data') + self.sock.sendmsg = mock.Mock() + self.sock.sendmsg.return_value = 2 + + transport = self.socket_transport(sendmsg=True) + transport.writelines([data]) + self.assertTrue(self.sock.sendmsg.called) + self.assertTrue(self.loop.writers) + + def test_writelines_send_full(self): + data = memoryview(b'data') + self.sock.send.return_value = len(data) + self.sock.send.fileno.return_value = 7 + + transport = self.socket_transport() + transport.writelines([data]) + self.assertTrue(self.sock.send.called) + self.assertFalse(self.loop.writers) + + def test_writelines_send_partial(self): + data = memoryview(b'data') + self.sock.send.return_value = 2 + self.sock.send.fileno.return_value = 7 + + transport = self.socket_transport() + transport.writelines([data]) + self.assertTrue(self.sock.send.called) + self.assertTrue(self.loop.writers) + @unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg') def test_write_sendmsg_full(self): data = memoryview(b'data') diff --git a/Misc/NEWS.d/next/Library/2023-04-12-06-00-02.gh-issue-103462.w6yBlM.rst b/Misc/NEWS.d/next/Library/2023-04-12-06-00-02.gh-issue-103462.w6yBlM.rst new file mode 100644 index 000000000000..50758c89cc28 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-12-06-00-02.gh-issue-103462.w6yBlM.rst @@ -0,0 +1,4 @@ +Fixed an issue with using :meth:`~asyncio.WriteTransport.writelines` in :mod:`asyncio` to send very +large payloads that exceed the amount of data that can be written in one +call to :meth:`socket.socket.send` or :meth:`socket.socket.sendmsg`, +resulting in the remaining buffer being left unwritten. From webhook-mailer at python.org Thu Apr 13 03:38:31 2023 From: webhook-mailer at python.org (cjw296) Date: Thu, 13 Apr 2023 07:38:31 -0000 Subject: [Python-checkins] gh-102978: Fix mock.patch function signatures for class and staticmethod decorators (#103228) Message-ID: https://github.com/python/cpython/commit/59e0de4903c02e72b329e505fddf1ad9794928bc commit: 59e0de4903c02e72b329e505fddf1ad9794928bc branch: main author: Tomas R committer: cjw296 date: 2023-04-13T08:37:57+01:00 summary: gh-102978: Fix mock.patch function signatures for class and staticmethod decorators (#103228) Fixes unittest.mock.patch not enforcing function signatures for methods decorated with @classmethod or @staticmethod when patch is called with autospec=True. files: A Misc/NEWS.d/next/Library/2023-04-03-23-44-34.gh-issue-102978.gy9eVk.rst M Lib/test/test_unittest/testmock/testhelpers.py M Lib/test/test_unittest/testmock/testpatch.py M Lib/unittest/mock.py M Misc/ACKS diff --git a/Lib/test/test_unittest/testmock/testhelpers.py b/Lib/test/test_unittest/testmock/testhelpers.py index dc4d004cda8a..74785a83757a 100644 --- a/Lib/test/test_unittest/testmock/testhelpers.py +++ b/Lib/test/test_unittest/testmock/testhelpers.py @@ -952,6 +952,24 @@ def __getattr__(self, attribute): self.assertFalse(hasattr(autospec, '__name__')) + def test_autospec_signature_staticmethod(self): + class Foo: + @staticmethod + def static_method(a, b=10, *, c): pass + + mock = create_autospec(Foo.__dict__['static_method']) + self.assertEqual(inspect.signature(Foo.static_method), inspect.signature(mock)) + + + def test_autospec_signature_classmethod(self): + class Foo: + @classmethod + def class_method(cls, a, b=10, *, c): pass + + mock = create_autospec(Foo.__dict__['class_method']) + self.assertEqual(inspect.signature(Foo.class_method), inspect.signature(mock)) + + def test_spec_inspect_signature(self): def myfunc(x, y): pass diff --git a/Lib/test/test_unittest/testmock/testpatch.py b/Lib/test/test_unittest/testmock/testpatch.py index 8ceb5d973e1a..833d7da1f31a 100644 --- a/Lib/test/test_unittest/testmock/testpatch.py +++ b/Lib/test/test_unittest/testmock/testpatch.py @@ -996,6 +996,36 @@ def test_autospec_classmethod(self): method.assert_called_once_with() + def test_autospec_staticmethod_signature(self): + # Patched methods which are decorated with @staticmethod should have the same signature + class Foo: + @staticmethod + def static_method(a, b=10, *, c): pass + + Foo.static_method(1, 2, c=3) + + with patch.object(Foo, 'static_method', autospec=True) as method: + method(1, 2, c=3) + self.assertRaises(TypeError, method) + self.assertRaises(TypeError, method, 1) + self.assertRaises(TypeError, method, 1, 2, 3, c=4) + + + def test_autospec_classmethod_signature(self): + # Patched methods which are decorated with @classmethod should have the same signature + class Foo: + @classmethod + def class_method(cls, a, b=10, *, c): pass + + Foo.class_method(1, 2, c=3) + + with patch.object(Foo, 'class_method', autospec=True) as method: + method(1, 2, c=3) + self.assertRaises(TypeError, method) + self.assertRaises(TypeError, method, 1) + self.assertRaises(TypeError, method, 1, 2, 3, c=4) + + def test_autospec_with_new(self): patcher = patch('%s.function' % __name__, new=3, autospec=True) self.assertRaises(TypeError, patcher.start) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 0f93cb53c3d5..7ca085760650 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -98,6 +98,12 @@ def _get_signature_object(func, as_instance, eat_self): func = func.__init__ # Skip the `self` argument in __init__ eat_self = True + elif isinstance(func, (classmethod, staticmethod)): + if isinstance(func, classmethod): + # Skip the `cls` argument of a class method + eat_self = True + # Use the original decorated method to extract the correct function signature + func = func.__func__ elif not isinstance(func, FunctionTypes): # If we really want to model an instance of the passed type, # __call__ should be looked up, not __init__. diff --git a/Misc/ACKS b/Misc/ACKS index 1e94d33a665e..d0ff4e8aeb5c 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1550,6 +1550,7 @@ Hugo van Rossum Saskia van Rossum Robin Roth Clement Rouault +Tomas Roun Donald Wallace Rouse II Liam Routt Todd Rovito diff --git a/Misc/NEWS.d/next/Library/2023-04-03-23-44-34.gh-issue-102978.gy9eVk.rst b/Misc/NEWS.d/next/Library/2023-04-03-23-44-34.gh-issue-102978.gy9eVk.rst new file mode 100644 index 000000000000..df63af10a385 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-03-23-44-34.gh-issue-102978.gy9eVk.rst @@ -0,0 +1,3 @@ +Fixes :func:`unittest.mock.patch` not enforcing function signatures for methods +decorated with ``@classmethod`` or ``@staticmethod`` when patch is called with +``autospec=True``. From webhook-mailer at python.org Thu Apr 13 08:56:18 2023 From: webhook-mailer at python.org (markshannon) Date: Thu, 13 Apr 2023 12:56:18 -0000 Subject: [Python-checkins] GH-103082: Turn on branch events for FOR_ITER instructions. (#103507) Message-ID: https://github.com/python/cpython/commit/70e0a28bed1354ec450989271152ae697e1f0993 commit: 70e0a28bed1354ec450989271152ae697e1f0993 branch: main author: Mark Shannon committer: markshannon date: 2023-04-13T13:56:09+01:00 summary: GH-103082: Turn on branch events for FOR_ITER instructions. (#103507) Turn on branch events for FOR_ITER instructions. files: M Lib/test/test_monitoring.py M Python/instrumentation.c diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index 4aad3da61b6b..738ace923cc5 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -1011,6 +1011,77 @@ def func3(): ('line', 'func3', 6)]) +def line_from_offset(code, offset): + for start, end, line in code.co_lines(): + if start <= offset < end: + return line - code.co_firstlineno + return -1 + +class JumpRecorder: + + event_type = E.JUMP + name = "jump" + + def __init__(self, events): + self.events = events + + def __call__(self, code, from_, to): + from_line = line_from_offset(code, from_) + to_line = line_from_offset(code, to) + self.events.append((self.name, code.co_name, from_line, to_line)) + + +class BranchRecorder(JumpRecorder): + + event_type = E.BRANCH + name = "branch" + + +JUMP_AND_BRANCH_RECORDERS = JumpRecorder, BranchRecorder +JUMP_BRANCH_AND_LINE_RECORDERS = JumpRecorder, BranchRecorder, LineRecorder + +class TestBranchAndJumpEvents(CheckEvents): + maxDiff = None + + def test_loop(self): + + def func(): + x = 1 + for a in range(2): + if a: + x = 4 + else: + x = 6 + + self.check_events(func, recorders = JUMP_AND_BRANCH_RECORDERS, expected = [ + ('branch', 'func', 2, 2), + ('branch', 'func', 3, 6), + ('jump', 'func', 6, 2), + ('branch', 'func', 2, 2), + ('branch', 'func', 3, 4), + ('jump', 'func', 4, 2), + ('branch', 'func', 2, 2)]) + + + self.check_events(func, recorders = JUMP_BRANCH_AND_LINE_RECORDERS, expected = [ + ('line', 'check_events', 10), + ('line', 'func', 1), + ('line', 'func', 2), + ('branch', 'func', 2, 2), + ('line', 'func', 3), + ('branch', 'func', 3, 6), + ('line', 'func', 6), + ('jump', 'func', 6, 2), + ('branch', 'func', 2, 2), + ('line', 'func', 3), + ('branch', 'func', 3, 4), + ('line', 'func', 4), + ('jump', 'func', 4, 2), + ('branch', 'func', 2, 2), + ('line', 'func', 2), + ('line', 'check_events', 11)]) + + class TestSetGetEvents(MonitoringTestBase, unittest.TestCase): def test_global(self): diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 39a7eaa3bd2d..8dc8b01fcb04 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -105,6 +105,8 @@ static const uint8_t INSTRUMENTED_OPCODES[256] = { [INSTRUMENTED_END_FOR] = INSTRUMENTED_END_FOR, [END_SEND] = INSTRUMENTED_END_SEND, [INSTRUMENTED_END_SEND] = INSTRUMENTED_END_SEND, + [FOR_ITER] = INSTRUMENTED_FOR_ITER, + [INSTRUMENTED_FOR_ITER] = INSTRUMENTED_FOR_ITER, [INSTRUMENTED_LINE] = INSTRUMENTED_LINE, [INSTRUMENTED_INSTRUCTION] = INSTRUMENTED_INSTRUCTION, From webhook-mailer at python.org Thu Apr 13 09:17:22 2023 From: webhook-mailer at python.org (zooba) Date: Thu, 13 Apr 2023 13:17:22 -0000 Subject: [Python-checkins] gh-103088: Fix test_venv error message to avoid bytes/str warning (GH-103500) Message-ID: https://github.com/python/cpython/commit/4307feaddc76b9e93cd38e325a1f0ee59d593093 commit: 4307feaddc76b9e93cd38e325a1f0ee59d593093 branch: main author: Stanislav Syekirin committer: zooba date: 2023-04-13T14:17:14+01:00 summary: gh-103088: Fix test_venv error message to avoid bytes/str warning (GH-103500) files: M Lib/test/test_venv.py diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index 23328431a7aa..7cccbe84f4eb 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -623,8 +623,9 @@ def test_activate_shell_script_has_no_dos_newlines(self): script_path = venv_dir / scripts_dir / "activate" venv.create(venv_dir) with open(script_path, 'rb') as script: - for line in script: - self.assertFalse(line.endswith(b'\r\n'), line) + for i, line in enumerate(script, 1): + error_message = f"CR LF found in line {i}" + self.assertFalse(line.endswith(b'\r\n'), error_message) @requireVenvCreate class EnsurePipTest(BaseTest): From webhook-mailer at python.org Thu Apr 13 11:19:39 2023 From: webhook-mailer at python.org (markshannon) Date: Thu, 13 Apr 2023 15:19:39 -0000 Subject: [Python-checkins] GH-103488: Use return-offset, not yield-offset. (GH-103502) Message-ID: https://github.com/python/cpython/commit/efb8a2553c88a295514be228c44fb99ef035e3fa commit: efb8a2553c88a295514be228c44fb99ef035e3fa branch: main author: Mark Shannon committer: markshannon date: 2023-04-13T16:19:07+01:00 summary: GH-103488: Use return-offset, not yield-offset. (GH-103502) * Use return-offset, not yield-offset, so that instruction pointer is correct when sending to a generator or coroutine. files: A Misc/NEWS.d/next/Core and Builtins/2023-04-12-20-18-51.gh-issue-103488.vYvlHD.rst M Include/internal/pycore_frame.h M Lib/test/test_generators.py M Python/bytecodes.c M Python/ceval.c M Python/generated_cases.c.h diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 856297aaea8a..20d48d203625 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -61,7 +61,13 @@ typedef struct _PyInterpreterFrame { // over, or (in the case of a newly-created frame) a totally invalid value: _Py_CODEUNIT *prev_instr; int stacktop; /* Offset of TOS from localsplus */ - uint16_t yield_offset; + /* The return_offset determines where a `RETURN` should go in the caller, + * relative to `prev_instr`. + * It is only meaningful to the callee, + * so it needs to be set in any CALL (to a Python function) + * or SEND (to a coroutine or generator). + * If there is no callee, then it is meaningless. */ + uint16_t return_offset; char owner; /* Locals and stack */ PyObject *localsplus[1]; @@ -121,7 +127,7 @@ _PyFrame_Initialize( frame->stacktop = code->co_nlocalsplus; frame->frame_obj = NULL; frame->prev_instr = _PyCode_CODE(code) - 1; - frame->yield_offset = 0; + frame->return_offset = 0; frame->owner = FRAME_OWNED_BY_THREAD; for (int i = null_locals_from; i < code->co_nlocalsplus; i++) { diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index a5949dec70d1..cc782ea1ee5d 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -225,7 +225,22 @@ def f(): gi = f() self.assertIsNone(gi.gi_frame.f_back) + def test_issue103488(self): + def gen_raises(): + yield + raise ValueError() + + def loop(): + try: + for _ in gen_raises(): + if True is False: + return + except ValueError: + pass + + #This should not raise + loop() class ExceptionTest(unittest.TestCase): # Tests for the issue #23353: check that the currently handled exception diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-12-20-18-51.gh-issue-103488.vYvlHD.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-12-20-18-51.gh-issue-103488.vYvlHD.rst new file mode 100644 index 000000000000..e7daa104e571 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-12-20-18-51.gh-issue-103488.vYvlHD.rst @@ -0,0 +1,3 @@ +Change the internal offset distinguishing yield and return target addresses, +so that the instruction pointer is correct for exception handling and other +stack unwinding. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 5c6398aba198..7af96b4a5e32 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -506,6 +506,7 @@ dummy_func( new_frame->localsplus[0] = container; new_frame->localsplus[1] = sub; JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); + frame->return_offset = 0; DISPATCH_INLINED(new_frame); } @@ -637,6 +638,7 @@ dummy_func( _PyInterpreterFrame *dying = frame; frame = cframe.current_frame = dying->previous; _PyEvalFrameClearAndPop(tstate, dying); + frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; } @@ -655,6 +657,7 @@ dummy_func( _PyInterpreterFrame *dying = frame; frame = cframe.current_frame = dying->previous; _PyEvalFrameClearAndPop(tstate, dying); + frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; } @@ -670,6 +673,7 @@ dummy_func( _PyInterpreterFrame *dying = frame; frame = cframe.current_frame = dying->previous; _PyEvalFrameClearAndPop(tstate, dying); + frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; } @@ -689,6 +693,7 @@ dummy_func( _PyInterpreterFrame *dying = frame; frame = cframe.current_frame = dying->previous; _PyEvalFrameClearAndPop(tstate, dying); + frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; } @@ -823,13 +828,13 @@ dummy_func( { PyGenObject *gen = (PyGenObject *)receiver; _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; - frame->yield_offset = oparg; + frame->return_offset = oparg; STACK_SHRINK(1); _PyFrame_StackPush(gen_frame, v); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; - JUMPBY(INLINE_CACHE_ENTRIES_SEND + oparg); + JUMPBY(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); } if (Py_IsNone(v) && PyIter_Check(receiver)) { @@ -861,13 +866,13 @@ dummy_func( DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND); STAT_INC(SEND, hit); _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; - frame->yield_offset = oparg; + frame->return_offset = oparg; STACK_SHRINK(1); _PyFrame_StackPush(gen_frame, v); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; - JUMPBY(INLINE_CACHE_ENTRIES_SEND + oparg); + JUMPBY(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); } @@ -886,7 +891,6 @@ dummy_func( _PyInterpreterFrame *gen_frame = frame; frame = cframe.current_frame = frame->previous; gen_frame->previous = NULL; - frame->prev_instr -= frame->yield_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; } @@ -905,7 +909,6 @@ dummy_func( _PyInterpreterFrame *gen_frame = frame; frame = cframe.current_frame = frame->previous; gen_frame->previous = NULL; - frame->prev_instr -= frame->yield_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; } @@ -1724,6 +1727,7 @@ dummy_func( STACK_SHRINK(shrink_stack); new_frame->localsplus[0] = owner; JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + frame->return_offset = 0; DISPATCH_INLINED(new_frame); } @@ -1751,6 +1755,7 @@ dummy_func( new_frame->localsplus[0] = owner; new_frame->localsplus[1] = Py_NewRef(name); JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + frame->return_offset = 0; DISPATCH_INLINED(new_frame); } @@ -2259,14 +2264,14 @@ dummy_func( DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER); STAT_INC(FOR_ITER, hit); _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; - frame->yield_offset = oparg; + frame->return_offset = oparg; _PyFrame_StackPush(gen_frame, Py_NewRef(Py_None)); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg); - assert(next_instr->op.code == END_FOR || - next_instr->op.code == INSTRUMENTED_END_FOR); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + assert(next_instr[oparg].op.code == END_FOR || + next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); } @@ -2521,6 +2526,7 @@ dummy_func( goto error; } JUMPBY(INLINE_CACHE_ENTRIES_CALL); + frame->return_offset = 0; DISPATCH_INLINED(new_frame); } /* Callable is not a normal Python function */ @@ -2594,6 +2600,7 @@ dummy_func( // Manipulate stack directly since we leave using DISPATCH_INLINED(). STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); + frame->return_offset = 0; DISPATCH_INLINED(new_frame); } @@ -2631,6 +2638,7 @@ dummy_func( // Manipulate stack and cache directly since we leave using DISPATCH_INLINED(). STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); + frame->return_offset = 0; DISPATCH_INLINED(new_frame); } diff --git a/Python/ceval.c b/Python/ceval.c index a38c9ec9ad5f..8c43e3d89c2c 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -672,7 +672,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int _PyCode_CODE(tstate->interp->interpreter_trampoline); entry_frame.stacktop = 0; entry_frame.owner = FRAME_OWNED_BY_CSTACK; - entry_frame.yield_offset = 0; + entry_frame.return_offset = 0; /* Push frame */ entry_frame.previous = prev_cframe->current_frame; frame->previous = &entry_frame; @@ -881,6 +881,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int _PyInterpreterFrame *dying = frame; frame = cframe.current_frame = dying->previous; _PyEvalFrameClearAndPop(tstate, dying); + frame->return_offset = 0; if (frame == &entry_frame) { /* Restore previous cframe and exit */ tstate->cframe = cframe.previous; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 4d52e95dc04a..0928f8200ae7 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -715,16 +715,17 @@ new_frame->localsplus[0] = container; new_frame->localsplus[1] = sub; JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); + frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 720 "Python/generated_cases.c.h" + #line 721 "Python/generated_cases.c.h" } TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 513 "Python/bytecodes.c" + #line 514 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; - #line 728 "Python/generated_cases.c.h" + #line 729 "Python/generated_cases.c.h" STACK_SHRINK(1); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -733,13 +734,13 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 518 "Python/bytecodes.c" + #line 519 "Python/bytecodes.c" int err = PySet_Add(set, v); - #line 739 "Python/generated_cases.c.h" + #line 740 "Python/generated_cases.c.h" Py_DECREF(v); - #line 520 "Python/bytecodes.c" + #line 521 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 743 "Python/generated_cases.c.h" + #line 744 "Python/generated_cases.c.h" STACK_SHRINK(1); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -752,7 +753,7 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 531 "Python/bytecodes.c" + #line 532 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr--; @@ -767,13 +768,13 @@ #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); - #line 771 "Python/generated_cases.c.h" + #line 772 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - #line 546 "Python/bytecodes.c" + #line 547 "Python/bytecodes.c" if (err) goto pop_3_error; - #line 777 "Python/generated_cases.c.h" + #line 778 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -783,7 +784,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 550 "Python/bytecodes.c" + #line 551 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -800,7 +801,7 @@ Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 804 "Python/generated_cases.c.h" + #line 805 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -810,13 +811,13 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 569 "Python/bytecodes.c" + #line 570 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); Py_DECREF(dict); if (err) goto pop_3_error; - #line 820 "Python/generated_cases.c.h" + #line 821 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -825,15 +826,15 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 577 "Python/bytecodes.c" + #line 578 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); - #line 832 "Python/generated_cases.c.h" + #line 833 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 580 "Python/bytecodes.c" + #line 581 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 837 "Python/generated_cases.c.h" + #line 838 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -841,14 +842,14 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 584 "Python/bytecodes.c" + #line 585 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); - #line 848 "Python/generated_cases.c.h" + #line 849 "Python/generated_cases.c.h" Py_DECREF(value); - #line 587 "Python/bytecodes.c" + #line 588 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 852 "Python/generated_cases.c.h" + #line 853 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -857,15 +858,15 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 591 "Python/bytecodes.c" + #line 592 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); - #line 864 "Python/generated_cases.c.h" + #line 865 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 594 "Python/bytecodes.c" + #line 595 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 869 "Python/generated_cases.c.h" + #line 870 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -873,7 +874,7 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); - #line 598 "Python/bytecodes.c" + #line 599 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -891,12 +892,12 @@ break; } if (true) { STACK_SHRINK(oparg); goto error; } - #line 895 "Python/generated_cases.c.h" + #line 896 "Python/generated_cases.c.h" } TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; - #line 618 "Python/bytecodes.c" + #line 619 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); STACK_SHRINK(1); // Since we're not going to DISPATCH() @@ -907,12 +908,12 @@ assert(!_PyErr_Occurred(tstate)); _Py_LeaveRecursiveCallTstate(tstate); return retval; - #line 911 "Python/generated_cases.c.h" + #line 912 "Python/generated_cases.c.h" } TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 631 "Python/bytecodes.c" + #line 632 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -922,14 +923,15 @@ _PyInterpreterFrame *dying = frame; frame = cframe.current_frame = dying->previous; _PyEvalFrameClearAndPop(tstate, dying); + frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 928 "Python/generated_cases.c.h" + #line 930 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 645 "Python/bytecodes.c" + #line 647 "Python/bytecodes.c" int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); @@ -943,13 +945,14 @@ _PyInterpreterFrame *dying = frame; frame = cframe.current_frame = dying->previous; _PyEvalFrameClearAndPop(tstate, dying); + frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 949 "Python/generated_cases.c.h" + #line 952 "Python/generated_cases.c.h" } TARGET(RETURN_CONST) { - #line 663 "Python/bytecodes.c" + #line 666 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -960,13 +963,14 @@ _PyInterpreterFrame *dying = frame; frame = cframe.current_frame = dying->previous; _PyEvalFrameClearAndPop(tstate, dying); + frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 966 "Python/generated_cases.c.h" + #line 970 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_CONST) { - #line 678 "Python/bytecodes.c" + #line 682 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, @@ -981,15 +985,16 @@ _PyInterpreterFrame *dying = frame; frame = cframe.current_frame = dying->previous; _PyEvalFrameClearAndPop(tstate, dying); + frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 987 "Python/generated_cases.c.h" + #line 992 "Python/generated_cases.c.h" } TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 697 "Python/bytecodes.c" + #line 702 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -1002,16 +1007,16 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); - #line 1006 "Python/generated_cases.c.h" + #line 1011 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 710 "Python/bytecodes.c" + #line 715 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); - #line 1013 "Python/generated_cases.c.h" + #line 1018 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 715 "Python/bytecodes.c" + #line 720 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -1024,7 +1029,7 @@ Py_DECREF(iter); if (true) goto pop_1_error; } - #line 1028 "Python/generated_cases.c.h" + #line 1033 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -1032,7 +1037,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 730 "Python/bytecodes.c" + #line 735 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -1076,7 +1081,7 @@ } } - #line 1080 "Python/generated_cases.c.h" + #line 1085 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; PREDICT(LOAD_CONST); @@ -1087,16 +1092,16 @@ PREDICTED(GET_AWAITABLE); PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 777 "Python/bytecodes.c" + #line 782 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } - #line 1098 "Python/generated_cases.c.h" + #line 1103 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 784 "Python/bytecodes.c" + #line 789 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1114,7 +1119,7 @@ if (iter == NULL) goto pop_1_error; - #line 1118 "Python/generated_cases.c.h" + #line 1123 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -1125,7 +1130,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 810 "Python/bytecodes.c" + #line 815 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1142,13 +1147,13 @@ { PyGenObject *gen = (PyGenObject *)receiver; _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; - frame->yield_offset = oparg; + frame->return_offset = oparg; STACK_SHRINK(1); _PyFrame_StackPush(gen_frame, v); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; - JUMPBY(INLINE_CACHE_ENTRIES_SEND + oparg); + JUMPBY(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); } if (Py_IsNone(v) && PyIter_Check(receiver)) { @@ -1171,7 +1176,7 @@ } } Py_DECREF(v); - #line 1175 "Python/generated_cases.c.h" + #line 1180 "Python/generated_cases.c.h" stack_pointer[-1] = retval; next_instr += 1; DISPATCH(); @@ -1180,27 +1185,27 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 858 "Python/bytecodes.c" + #line 863 "Python/bytecodes.c" PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type, SEND); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND); STAT_INC(SEND, hit); _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; - frame->yield_offset = oparg; + frame->return_offset = oparg; STACK_SHRINK(1); _PyFrame_StackPush(gen_frame, v); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; - JUMPBY(INLINE_CACHE_ENTRIES_SEND + oparg); + JUMPBY(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); - #line 1199 "Python/generated_cases.c.h" + #line 1204 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 875 "Python/bytecodes.c" + #line 880 "Python/bytecodes.c" assert(frame != &entry_frame); PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_SUSPENDED; @@ -1215,15 +1220,14 @@ _PyInterpreterFrame *gen_frame = frame; frame = cframe.current_frame = frame->previous; gen_frame->previous = NULL; - frame->prev_instr -= frame->yield_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1222 "Python/generated_cases.c.h" + #line 1226 "Python/generated_cases.c.h" } TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 895 "Python/bytecodes.c" + #line 899 "Python/bytecodes.c" // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -1237,18 +1241,17 @@ _PyInterpreterFrame *gen_frame = frame; frame = cframe.current_frame = frame->previous; gen_frame->previous = NULL; - frame->prev_instr -= frame->yield_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1244 "Python/generated_cases.c.h" + #line 1247 "Python/generated_cases.c.h" } TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 914 "Python/bytecodes.c" + #line 917 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - #line 1252 "Python/generated_cases.c.h" + #line 1255 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1256,7 +1259,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 919 "Python/bytecodes.c" + #line 922 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1274,26 +1277,26 @@ Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; - #line 1278 "Python/generated_cases.c.h" + #line 1281 "Python/generated_cases.c.h" } TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 939 "Python/bytecodes.c" + #line 942 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { - #line 1287 "Python/generated_cases.c.h" + #line 1290 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 942 "Python/bytecodes.c" + #line 945 "Python/bytecodes.c" } else { Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } - #line 1297 "Python/generated_cases.c.h" + #line 1300 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -1304,23 +1307,23 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 951 "Python/bytecodes.c" + #line 954 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { value = Py_NewRef(((PyStopIterationObject *)exc_value)->value); - #line 1313 "Python/generated_cases.c.h" + #line 1316 "Python/generated_cases.c.h" Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 956 "Python/bytecodes.c" + #line 959 "Python/bytecodes.c" none = Py_NewRef(Py_None); } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); goto exception_unwind; } - #line 1324 "Python/generated_cases.c.h" + #line 1327 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; stack_pointer[-2] = none; @@ -1329,9 +1332,9 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 965 "Python/bytecodes.c" + #line 968 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 1335 "Python/generated_cases.c.h" + #line 1338 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1339,7 +1342,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 969 "Python/bytecodes.c" + #line 972 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1361,7 +1364,7 @@ if (true) goto error; } } - #line 1365 "Python/generated_cases.c.h" + #line 1368 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; DISPATCH(); @@ -1369,33 +1372,33 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 993 "Python/bytecodes.c" + #line 996 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); - #line 1380 "Python/generated_cases.c.h" + #line 1383 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1000 "Python/bytecodes.c" + #line 1003 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); - #line 1389 "Python/generated_cases.c.h" + #line 1392 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1007 "Python/bytecodes.c" + #line 1010 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1393 "Python/generated_cases.c.h" + #line 1396 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_NAME) { - #line 1011 "Python/bytecodes.c" + #line 1014 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1412,7 +1415,7 @@ name); goto error; } - #line 1416 "Python/generated_cases.c.h" + #line 1419 "Python/generated_cases.c.h" DISPATCH(); } @@ -1420,7 +1423,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1037 "Python/bytecodes.c" + #line 1040 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1433,11 +1436,11 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - #line 1437 "Python/generated_cases.c.h" + #line 1440 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1050 "Python/bytecodes.c" + #line 1053 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1441 "Python/generated_cases.c.h" + #line 1444 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; @@ -1447,14 +1450,14 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1054 "Python/bytecodes.c" + #line 1057 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - #line 1458 "Python/generated_cases.c.h" + #line 1461 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1465,7 +1468,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1064 "Python/bytecodes.c" + #line 1067 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1473,7 +1476,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1477 "Python/generated_cases.c.h" + #line 1480 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1484,7 +1487,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1075 "Python/bytecodes.c" + #line 1078 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1492,7 +1495,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1496 "Python/generated_cases.c.h" + #line 1499 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1502,15 +1505,15 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 1086 "Python/bytecodes.c" + #line 1089 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - #line 1510 "Python/generated_cases.c.h" + #line 1513 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1090 "Python/bytecodes.c" + #line 1093 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1514 "Python/generated_cases.c.h" + #line 1517 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } @@ -1521,7 +1524,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 1101 "Python/bytecodes.c" + #line 1104 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); @@ -1537,12 +1540,12 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); - #line 1541 "Python/generated_cases.c.h" + #line 1544 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 1117 "Python/bytecodes.c" + #line 1120 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 1546 "Python/generated_cases.c.h" + #line 1549 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -1550,34 +1553,34 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 1121 "Python/bytecodes.c" + #line 1124 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - #line 1557 "Python/generated_cases.c.h" + #line 1560 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1124 "Python/bytecodes.c" + #line 1127 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1561 "Python/generated_cases.c.h" + #line 1564 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 1128 "Python/bytecodes.c" + #line 1131 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 1571 "Python/generated_cases.c.h" + #line 1574 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1131 "Python/bytecodes.c" + #line 1134 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1575 "Python/generated_cases.c.h" + #line 1578 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_GLOBAL) { - #line 1135 "Python/bytecodes.c" + #line 1138 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1589,13 +1592,13 @@ } goto error; } - #line 1593 "Python/generated_cases.c.h" + #line 1596 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_NAME) { PyObject *v; - #line 1149 "Python/bytecodes.c" + #line 1152 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *locals = LOCALS(); if (locals == NULL) { @@ -1654,7 +1657,7 @@ } } } - #line 1658 "Python/generated_cases.c.h" + #line 1661 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = v; DISPATCH(); @@ -1665,7 +1668,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1216 "Python/bytecodes.c" + #line 1219 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1717,7 +1720,7 @@ } } null = NULL; - #line 1721 "Python/generated_cases.c.h" + #line 1724 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1731,7 +1734,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1270 "Python/bytecodes.c" + #line 1273 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -1742,7 +1745,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1746 "Python/generated_cases.c.h" + #line 1749 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1757,7 +1760,7 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); - #line 1283 "Python/bytecodes.c" + #line 1286 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); @@ -1772,7 +1775,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1776 "Python/generated_cases.c.h" + #line 1779 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1782,16 +1785,16 @@ } TARGET(DELETE_FAST) { - #line 1300 "Python/bytecodes.c" + #line 1303 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1790 "Python/generated_cases.c.h" + #line 1793 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { - #line 1306 "Python/bytecodes.c" + #line 1309 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -1800,12 +1803,12 @@ goto resume_with_error; } SETLOCAL(oparg, cell); - #line 1804 "Python/generated_cases.c.h" + #line 1807 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { - #line 1317 "Python/bytecodes.c" + #line 1320 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1816,13 +1819,13 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1820 "Python/generated_cases.c.h" + #line 1823 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_CLASSDEREF) { PyObject *value; - #line 1330 "Python/bytecodes.c" + #line 1333 "Python/bytecodes.c" PyObject *name, *locals = LOCALS(); assert(locals); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); @@ -1854,7 +1857,7 @@ } Py_INCREF(value); } - #line 1858 "Python/generated_cases.c.h" + #line 1861 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1862,7 +1865,7 @@ TARGET(LOAD_DEREF) { PyObject *value; - #line 1364 "Python/bytecodes.c" + #line 1367 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1870,7 +1873,7 @@ if (true) goto error; } Py_INCREF(value); - #line 1874 "Python/generated_cases.c.h" + #line 1877 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1878,18 +1881,18 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1374 "Python/bytecodes.c" + #line 1377 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 1887 "Python/generated_cases.c.h" + #line 1890 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #line 1381 "Python/bytecodes.c" + #line 1384 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); @@ -1900,22 +1903,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 1904 "Python/generated_cases.c.h" + #line 1907 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1394 "Python/bytecodes.c" + #line 1397 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 1913 "Python/generated_cases.c.h" + #line 1916 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1396 "Python/bytecodes.c" + #line 1399 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1919 "Python/generated_cases.c.h" + #line 1922 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -1925,10 +1928,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1400 "Python/bytecodes.c" + #line 1403 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1932 "Python/generated_cases.c.h" + #line 1935 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -1938,10 +1941,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1405 "Python/bytecodes.c" + #line 1408 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1945 "Python/generated_cases.c.h" + #line 1948 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -1951,7 +1954,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1410 "Python/bytecodes.c" + #line 1413 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1962,13 +1965,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 1966 "Python/generated_cases.c.h" + #line 1969 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1421 "Python/bytecodes.c" + #line 1424 "Python/bytecodes.c" if (true) goto pop_1_error; } Py_DECREF(none_val); - #line 1972 "Python/generated_cases.c.h" + #line 1975 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -1977,13 +1980,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1428 "Python/bytecodes.c" + #line 1431 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 1983 "Python/generated_cases.c.h" + #line 1986 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1430 "Python/bytecodes.c" + #line 1433 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 1987 "Python/generated_cases.c.h" + #line 1990 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1991,7 +1994,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1434 "Python/bytecodes.c" + #line 1437 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2006,7 +2009,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 2010 "Python/generated_cases.c.h" + #line 2013 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -2016,7 +2019,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1451 "Python/bytecodes.c" + #line 1454 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2024,13 +2027,13 @@ if (map == NULL) goto error; - #line 2028 "Python/generated_cases.c.h" + #line 2031 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1459 "Python/bytecodes.c" + #line 1462 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 2034 "Python/generated_cases.c.h" + #line 2037 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -2038,7 +2041,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1463 "Python/bytecodes.c" + #line 1466 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2078,7 +2081,7 @@ Py_DECREF(ann_dict); } } - #line 2082 "Python/generated_cases.c.h" + #line 2085 "Python/generated_cases.c.h" DISPATCH(); } @@ -2086,7 +2089,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1505 "Python/bytecodes.c" + #line 1508 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2096,14 +2099,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 2100 "Python/generated_cases.c.h" + #line 2103 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1515 "Python/bytecodes.c" + #line 1518 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 2107 "Python/generated_cases.c.h" + #line 2110 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -2111,7 +2114,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1519 "Python/bytecodes.c" + #line 1522 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -2119,12 +2122,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 2123 "Python/generated_cases.c.h" + #line 2126 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1527 "Python/bytecodes.c" + #line 1530 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2128 "Python/generated_cases.c.h" + #line 2131 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2132,17 +2135,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1533 "Python/bytecodes.c" + #line 1536 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 2141 "Python/generated_cases.c.h" + #line 2144 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1538 "Python/bytecodes.c" + #line 1541 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2146 "Python/generated_cases.c.h" + #line 2149 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); PREDICT(CALL_FUNCTION_EX); @@ -2152,13 +2155,13 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1545 "Python/bytecodes.c" + #line 1548 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 2162 "Python/generated_cases.c.h" + #line 2165 "Python/generated_cases.c.h" STACK_SHRINK(2); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -2170,7 +2173,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1568 "Python/bytecodes.c" + #line 1571 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2204,9 +2207,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2208 "Python/generated_cases.c.h" + #line 2211 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1602 "Python/bytecodes.c" + #line 1605 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2215,12 +2218,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2219 "Python/generated_cases.c.h" + #line 2222 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1611 "Python/bytecodes.c" + #line 1614 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2224 "Python/generated_cases.c.h" + #line 2227 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2234,7 +2237,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1616 "Python/bytecodes.c" + #line 1619 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2247,7 +2250,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2251 "Python/generated_cases.c.h" + #line 2254 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2262,7 +2265,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1632 "Python/bytecodes.c" + #line 1635 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2275,7 +2278,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2279 "Python/generated_cases.c.h" + #line 2282 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2290,7 +2293,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1648 "Python/bytecodes.c" + #line 1651 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2317,7 +2320,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2321 "Python/generated_cases.c.h" + #line 2324 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2332,7 +2335,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1678 "Python/bytecodes.c" + #line 1681 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2342,7 +2345,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2346 "Python/generated_cases.c.h" + #line 2349 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2357,7 +2360,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1691 "Python/bytecodes.c" + #line 1694 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2369,7 +2372,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2373 "Python/generated_cases.c.h" + #line 2376 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2383,7 +2386,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1706 "Python/bytecodes.c" + #line 1709 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2405,8 +2408,9 @@ STACK_SHRINK(shrink_stack); new_frame->localsplus[0] = owner; JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2410 "Python/generated_cases.c.h" + #line 2414 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2414,7 +2418,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1731 "Python/bytecodes.c" + #line 1735 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2438,8 +2442,9 @@ new_frame->localsplus[0] = owner; new_frame->localsplus[1] = Py_NewRef(name); JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2443 "Python/generated_cases.c.h" + #line 2448 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2447,7 +2452,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1758 "Python/bytecodes.c" + #line 1763 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2465,7 +2470,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2469 "Python/generated_cases.c.h" + #line 2474 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2476,7 +2481,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1778 "Python/bytecodes.c" + #line 1783 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2515,7 +2520,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2519 "Python/generated_cases.c.h" + #line 2524 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2526,7 +2531,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1819 "Python/bytecodes.c" + #line 1824 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2536,7 +2541,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2540 "Python/generated_cases.c.h" + #line 2545 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2548,7 +2553,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1838 "Python/bytecodes.c" + #line 1843 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2561,12 +2566,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2565 "Python/generated_cases.c.h" + #line 2570 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1851 "Python/bytecodes.c" + #line 1856 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2570 "Python/generated_cases.c.h" + #line 2575 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2577,7 +2582,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1855 "Python/bytecodes.c" + #line 1860 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2589,7 +2594,7 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2593 "Python/generated_cases.c.h" + #line 2598 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2600,7 +2605,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1870 "Python/bytecodes.c" + #line 1875 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2616,7 +2621,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2620 "Python/generated_cases.c.h" + #line 2625 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2627,7 +2632,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1889 "Python/bytecodes.c" + #line 1894 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2640,7 +2645,7 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2644 "Python/generated_cases.c.h" + #line 2649 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2651,14 +2656,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1904 "Python/bytecodes.c" + #line 1909 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2657 "Python/generated_cases.c.h" + #line 2662 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1906 "Python/bytecodes.c" + #line 1911 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2662 "Python/generated_cases.c.h" + #line 2667 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2668,15 +2673,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1910 "Python/bytecodes.c" + #line 1915 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2674 "Python/generated_cases.c.h" + #line 2679 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1912 "Python/bytecodes.c" + #line 1917 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = Py_NewRef((res^oparg) ? Py_True : Py_False); - #line 2680 "Python/generated_cases.c.h" + #line 2685 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2687,12 +2692,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 1917 "Python/bytecodes.c" + #line 1922 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2693 "Python/generated_cases.c.h" + #line 2698 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1919 "Python/bytecodes.c" + #line 1924 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2700,10 +2705,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2704 "Python/generated_cases.c.h" + #line 2709 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1927 "Python/bytecodes.c" + #line 1932 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2712,7 +2717,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 2716 "Python/generated_cases.c.h" + #line 2721 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2722,21 +2727,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1938 "Python/bytecodes.c" + #line 1943 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2729 "Python/generated_cases.c.h" + #line 2734 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1941 "Python/bytecodes.c" + #line 1946 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 2736 "Python/generated_cases.c.h" + #line 2741 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1946 "Python/bytecodes.c" + #line 1951 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2740 "Python/generated_cases.c.h" + #line 2745 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -2745,15 +2750,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 1950 "Python/bytecodes.c" + #line 1955 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 2752 "Python/generated_cases.c.h" + #line 2757 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 1953 "Python/bytecodes.c" + #line 1958 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2757 "Python/generated_cases.c.h" + #line 2762 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -2762,29 +2767,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 1957 "Python/bytecodes.c" + #line 1962 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 2770 "Python/generated_cases.c.h" + #line 2775 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 1963 "Python/bytecodes.c" + #line 1968 "Python/bytecodes.c" JUMPBY(oparg); - #line 2779 "Python/generated_cases.c.h" + #line 2784 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 1967 "Python/bytecodes.c" + #line 1972 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 2788 "Python/generated_cases.c.h" + #line 2793 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -2792,7 +2797,7 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 1973 "Python/bytecodes.c" + #line 1978 "Python/bytecodes.c" if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2802,9 +2807,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2806 "Python/generated_cases.c.h" + #line 2811 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 1983 "Python/bytecodes.c" + #line 1988 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -2812,14 +2817,14 @@ if (err < 0) goto pop_1_error; } } - #line 2816 "Python/generated_cases.c.h" + #line 2821 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 1993 "Python/bytecodes.c" + #line 1998 "Python/bytecodes.c" if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2829,9 +2834,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2833 "Python/generated_cases.c.h" + #line 2838 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2003 "Python/bytecodes.c" + #line 2008 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -2839,67 +2844,67 @@ if (err < 0) goto pop_1_error; } } - #line 2843 "Python/generated_cases.c.h" + #line 2848 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2013 "Python/bytecodes.c" + #line 2018 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 2852 "Python/generated_cases.c.h" + #line 2857 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2015 "Python/bytecodes.c" + #line 2020 "Python/bytecodes.c" JUMPBY(oparg); } else { _Py_DECREF_NO_DEALLOC(value); } - #line 2860 "Python/generated_cases.c.h" + #line 2865 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2023 "Python/bytecodes.c" + #line 2028 "Python/bytecodes.c" if (Py_IsNone(value)) { _Py_DECREF_NO_DEALLOC(value); JUMPBY(oparg); } else { - #line 2873 "Python/generated_cases.c.h" + #line 2878 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2029 "Python/bytecodes.c" + #line 2034 "Python/bytecodes.c" } - #line 2877 "Python/generated_cases.c.h" + #line 2882 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2033 "Python/bytecodes.c" + #line 2038 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 2890 "Python/generated_cases.c.h" + #line 2895 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2042 "Python/bytecodes.c" + #line 2047 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 2903 "Python/generated_cases.c.h" + #line 2908 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -2910,16 +2915,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2050 "Python/bytecodes.c" + #line 2055 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 2919 "Python/generated_cases.c.h" + #line 2924 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2055 "Python/bytecodes.c" + #line 2060 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -2927,7 +2932,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_NewRef(Py_None); // Failure! } - #line 2931 "Python/generated_cases.c.h" + #line 2936 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -2936,10 +2941,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2065 "Python/bytecodes.c" + #line 2070 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); - #line 2943 "Python/generated_cases.c.h" + #line 2948 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -2949,10 +2954,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2071 "Python/bytecodes.c" + #line 2076 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); - #line 2956 "Python/generated_cases.c.h" + #line 2961 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -2963,11 +2968,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2077 "Python/bytecodes.c" + #line 2082 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 2971 "Python/generated_cases.c.h" + #line 2976 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -2976,14 +2981,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2083 "Python/bytecodes.c" + #line 2088 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 2983 "Python/generated_cases.c.h" + #line 2988 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2086 "Python/bytecodes.c" + #line 2091 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 2987 "Python/generated_cases.c.h" + #line 2992 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -2991,7 +2996,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2090 "Python/bytecodes.c" + #line 2095 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3014,11 +3019,11 @@ if (iter == NULL) { goto error; } - #line 3018 "Python/generated_cases.c.h" + #line 3023 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2113 "Python/bytecodes.c" + #line 2118 "Python/bytecodes.c" } - #line 3022 "Python/generated_cases.c.h" + #line 3027 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -3029,7 +3034,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2132 "Python/bytecodes.c" + #line 2137 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3060,7 +3065,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3064 "Python/generated_cases.c.h" + #line 3069 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3068,7 +3073,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2165 "Python/bytecodes.c" + #line 2170 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3094,14 +3099,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3098 "Python/generated_cases.c.h" + #line 3103 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2193 "Python/bytecodes.c" + #line 2198 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3121,7 +3126,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3125 "Python/generated_cases.c.h" + #line 3130 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3131,7 +3136,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2215 "Python/bytecodes.c" + #line 2220 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3151,7 +3156,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3155 "Python/generated_cases.c.h" + #line 3160 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3161,7 +3166,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2237 "Python/bytecodes.c" + #line 2242 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3179,7 +3184,7 @@ if (next == NULL) { goto error; } - #line 3183 "Python/generated_cases.c.h" + #line 3188 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3188,29 +3193,29 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2257 "Python/bytecodes.c" + #line 2262 "Python/bytecodes.c" PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER); STAT_INC(FOR_ITER, hit); _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; - frame->yield_offset = oparg; + frame->return_offset = oparg; _PyFrame_StackPush(gen_frame, Py_NewRef(Py_None)); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg); - assert(next_instr->op.code == END_FOR || - next_instr->op.code == INSTRUMENTED_END_FOR); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + assert(next_instr[oparg].op.code == END_FOR || + next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3207 "Python/generated_cases.c.h" + #line 3212 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2274 "Python/bytecodes.c" + #line 2279 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3233,16 +3238,16 @@ Py_DECREF(enter); goto error; } - #line 3237 "Python/generated_cases.c.h" + #line 3242 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2297 "Python/bytecodes.c" + #line 2302 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3246 "Python/generated_cases.c.h" + #line 3251 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3254,7 +3259,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2307 "Python/bytecodes.c" + #line 2312 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3280,16 +3285,16 @@ Py_DECREF(enter); goto error; } - #line 3284 "Python/generated_cases.c.h" + #line 3289 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2333 "Python/bytecodes.c" + #line 2338 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3293 "Python/generated_cases.c.h" + #line 3298 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3301,7 +3306,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2342 "Python/bytecodes.c" + #line 2347 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3322,7 +3327,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3326 "Python/generated_cases.c.h" + #line 3331 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3331,7 +3336,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2365 "Python/bytecodes.c" + #line 2370 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3341,7 +3346,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3345 "Python/generated_cases.c.h" + #line 3350 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3355,7 +3360,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2377 "Python/bytecodes.c" + #line 2382 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3372,7 +3377,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3376 "Python/generated_cases.c.h" + #line 3381 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3386,7 +3391,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2396 "Python/bytecodes.c" + #line 2401 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3396,7 +3401,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3400 "Python/generated_cases.c.h" + #line 3405 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3410,7 +3415,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2408 "Python/bytecodes.c" + #line 2413 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3424,7 +3429,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3428 "Python/generated_cases.c.h" + #line 3433 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3433,16 +3438,16 @@ } TARGET(KW_NAMES) { - #line 2424 "Python/bytecodes.c" + #line 2429 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); - #line 3441 "Python/generated_cases.c.h" + #line 3446 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2430 "Python/bytecodes.c" + #line 2435 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3455,7 +3460,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3459 "Python/generated_cases.c.h" + #line 3464 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3465,7 +3470,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2475 "Python/bytecodes.c" + #line 2480 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3515,6 +3520,7 @@ goto error; } JUMPBY(INLINE_CACHE_ENTRIES_CALL); + frame->return_offset = 0; DISPATCH_INLINED(new_frame); } /* Callable is not a normal Python function */ @@ -3546,7 +3552,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3550 "Python/generated_cases.c.h" + #line 3556 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3558,7 +3564,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2562 "Python/bytecodes.c" + #line 2568 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3568,7 +3574,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3572 "Python/generated_cases.c.h" + #line 3578 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3577,7 +3583,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2574 "Python/bytecodes.c" + #line 2580 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3601,8 +3607,9 @@ // Manipulate stack directly since we leave using DISPATCH_INLINED(). STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); + frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3606 "Python/generated_cases.c.h" + #line 3613 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3610,7 +3617,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2601 "Python/bytecodes.c" + #line 2608 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3644,8 +3651,9 @@ // Manipulate stack and cache directly since we leave using DISPATCH_INLINED(). STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); + frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3649 "Python/generated_cases.c.h" + #line 3657 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3653,7 +3661,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2638 "Python/bytecodes.c" + #line 2646 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3663,7 +3671,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3667 "Python/generated_cases.c.h" + #line 3675 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3676,7 +3684,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2650 "Python/bytecodes.c" + #line 2658 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3687,7 +3695,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3691 "Python/generated_cases.c.h" + #line 3699 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3701,7 +3709,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2664 "Python/bytecodes.c" + #line 2672 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3712,7 +3720,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3716 "Python/generated_cases.c.h" + #line 3724 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3726,7 +3734,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2678 "Python/bytecodes.c" + #line 2686 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3748,7 +3756,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3752 "Python/generated_cases.c.h" + #line 3760 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3762,7 +3770,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2703 "Python/bytecodes.c" + #line 2711 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -3790,7 +3798,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3794 "Python/generated_cases.c.h" + #line 3802 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3804,7 +3812,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2734 "Python/bytecodes.c" + #line 2742 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -3836,7 +3844,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 3840 "Python/generated_cases.c.h" + #line 3848 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3850,7 +3858,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2769 "Python/bytecodes.c" + #line 2777 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -3882,7 +3890,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3886 "Python/generated_cases.c.h" + #line 3894 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3896,7 +3904,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2804 "Python/bytecodes.c" + #line 2812 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -3921,7 +3929,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3925 "Python/generated_cases.c.h" + #line 3933 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3934,7 +3942,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2831 "Python/bytecodes.c" + #line 2839 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -3961,7 +3969,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3965 "Python/generated_cases.c.h" + #line 3973 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3973,7 +3981,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2861 "Python/bytecodes.c" + #line 2869 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -3991,14 +3999,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 3995 "Python/generated_cases.c.h" + #line 4003 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2881 "Python/bytecodes.c" + #line 2889 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4029,7 +4037,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4033 "Python/generated_cases.c.h" + #line 4041 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4042,7 +4050,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2915 "Python/bytecodes.c" + #line 2923 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4071,7 +4079,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4075 "Python/generated_cases.c.h" + #line 4083 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4084,7 +4092,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2947 "Python/bytecodes.c" + #line 2955 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4113,7 +4121,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4117 "Python/generated_cases.c.h" + #line 4125 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4126,7 +4134,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2979 "Python/bytecodes.c" + #line 2987 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4154,7 +4162,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4158 "Python/generated_cases.c.h" + #line 4166 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4164,9 +4172,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3010 "Python/bytecodes.c" + #line 3018 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4170 "Python/generated_cases.c.h" + #line 4178 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4175,7 +4183,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3014 "Python/bytecodes.c" + #line 3022 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4218,14 +4226,14 @@ else { result = PyObject_Call(func, callargs, kwargs); } - #line 4222 "Python/generated_cases.c.h" + #line 4230 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3057 "Python/bytecodes.c" + #line 3065 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4229 "Python/generated_cases.c.h" + #line 4237 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4240,7 +4248,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; - #line 3067 "Python/bytecodes.c" + #line 3075 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4269,14 +4277,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4273 "Python/generated_cases.c.h" + #line 4281 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3098 "Python/bytecodes.c" + #line 3106 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4297,7 +4305,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4301 "Python/generated_cases.c.h" + #line 4309 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4305,15 +4313,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3121 "Python/bytecodes.c" + #line 3129 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4311 "Python/generated_cases.c.h" + #line 4319 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3123 "Python/bytecodes.c" + #line 3131 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4317 "Python/generated_cases.c.h" + #line 4325 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4324,7 +4332,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 3127 "Python/bytecodes.c" + #line 3135 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4359,7 +4367,7 @@ Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4363 "Python/generated_cases.c.h" + #line 4371 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4368,10 +4376,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3164 "Python/bytecodes.c" + #line 3172 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4375 "Python/generated_cases.c.h" + #line 4383 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4383,7 +4391,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3169 "Python/bytecodes.c" + #line 3177 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4398,12 +4406,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4402 "Python/generated_cases.c.h" + #line 4410 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3184 "Python/bytecodes.c" + #line 3192 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4407 "Python/generated_cases.c.h" + #line 4415 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4413,16 +4421,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3189 "Python/bytecodes.c" + #line 3197 "Python/bytecodes.c" assert(oparg >= 2); - #line 4419 "Python/generated_cases.c.h" + #line 4427 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_LINE) { - #line 3193 "Python/bytecodes.c" + #line 3201 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _PyFrame_SetStackPointer(frame, stack_pointer); int original_opcode = _Py_call_instrumentation_line( @@ -4442,11 +4450,11 @@ } opcode = original_opcode; DISPATCH_GOTO(); - #line 4446 "Python/generated_cases.c.h" + #line 4454 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3215 "Python/bytecodes.c" + #line 3223 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4458,26 +4466,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4462 "Python/generated_cases.c.h" + #line 4470 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3229 "Python/bytecodes.c" + #line 3237 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4468 "Python/generated_cases.c.h" + #line 4476 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3233 "Python/bytecodes.c" + #line 3241 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); - #line 4475 "Python/generated_cases.c.h" + #line 4483 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3238 "Python/bytecodes.c" + #line 3246 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4486,12 +4494,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4490 "Python/generated_cases.c.h" + #line 4498 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3249 "Python/bytecodes.c" + #line 3257 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4500,12 +4508,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4504 "Python/generated_cases.c.h" + #line 4512 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3260 "Python/bytecodes.c" + #line 3268 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4518,12 +4526,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4522 "Python/generated_cases.c.h" + #line 4530 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3275 "Python/bytecodes.c" + #line 3283 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4536,30 +4544,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4540 "Python/generated_cases.c.h" + #line 4548 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3290 "Python/bytecodes.c" + #line 3298 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4551 "Python/generated_cases.c.h" + #line 4559 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3298 "Python/bytecodes.c" + #line 3306 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4558 "Python/generated_cases.c.h" + #line 4566 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3303 "Python/bytecodes.c" + #line 3311 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4565 "Python/generated_cases.c.h" + #line 4573 "Python/generated_cases.c.h" } From webhook-mailer at python.org Thu Apr 13 11:24:40 2023 From: webhook-mailer at python.org (ethanfurman) Date: Thu, 13 Apr 2023 15:24:40 -0000 Subject: [Python-checkins] gh-103365: [Enum] STRICT boundary corrections (GH-103494) Message-ID: https://github.com/python/cpython/commit/2194071540313e2bbdc7214d77453b9ce3034a5c commit: 2194071540313e2bbdc7214d77453b9ce3034a5c branch: main author: Ethan Furman committer: ethanfurman date: 2023-04-13T08:24:33-07:00 summary: gh-103365: [Enum] STRICT boundary corrections (GH-103494) STRICT boundary: - fix bitwise operations - make default for Flag files: A Misc/NEWS.d/next/Library/2023-04-12-17-59-55.gh-issue-103365.UBEE0U.rst M Doc/library/enum.rst M Lib/enum.py M Lib/test/test_enum.py diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index c690c837309e..07acf9da33e2 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -696,7 +696,8 @@ Data Types .. attribute:: STRICT - Out-of-range values cause a :exc:`ValueError` to be raised:: + Out-of-range values cause a :exc:`ValueError` to be raised. This is the + default for :class:`Flag`:: >>> from enum import Flag, STRICT, auto >>> class StrictFlag(Flag, boundary=STRICT): @@ -714,7 +715,7 @@ Data Types .. attribute:: CONFORM Out-of-range values have invalid values removed, leaving a valid *Flag* - value. This is the default for :class:`Flag`:: + value:: >>> from enum import Flag, CONFORM, auto >>> class ConformFlag(Flag, boundary=CONFORM): diff --git a/Lib/enum.py b/Lib/enum.py index 10902c4b202a..432d7456b4b9 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -275,6 +275,13 @@ def __set_name__(self, enum_class, member_name): enum_member.__objclass__ = enum_class enum_member.__init__(*args) enum_member._sort_order_ = len(enum_class._member_names_) + + if Flag is not None and issubclass(enum_class, Flag): + enum_class._flag_mask_ |= value + if _is_single_bit(value): + enum_class._singles_mask_ |= value + enum_class._all_bits_ = 2 ** ((enum_class._flag_mask_).bit_length()) - 1 + # If another member with the same value was already defined, the # new member becomes an alias to the existing one. try: @@ -532,12 +539,8 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k classdict['_use_args_'] = use_args # # convert future enum members into temporary _proto_members - # and record integer values in case this will be a Flag - flag_mask = 0 for name in member_names: value = classdict[name] - if isinstance(value, int): - flag_mask |= value classdict[name] = _proto_member(value) # # house-keeping structures @@ -554,8 +557,9 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k boundary or getattr(first_enum, '_boundary_', None) ) - classdict['_flag_mask_'] = flag_mask - classdict['_all_bits_'] = 2 ** ((flag_mask).bit_length()) - 1 + classdict['_flag_mask_'] = 0 + classdict['_singles_mask_'] = 0 + classdict['_all_bits_'] = 0 classdict['_inverted_'] = None try: exc = None @@ -644,21 +648,10 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k ): delattr(enum_class, '_boundary_') delattr(enum_class, '_flag_mask_') + delattr(enum_class, '_singles_mask_') delattr(enum_class, '_all_bits_') delattr(enum_class, '_inverted_') elif Flag is not None and issubclass(enum_class, Flag): - # ensure _all_bits_ is correct and there are no missing flags - single_bit_total = 0 - multi_bit_total = 0 - for flag in enum_class._member_map_.values(): - flag_value = flag._value_ - if _is_single_bit(flag_value): - single_bit_total |= flag_value - else: - # multi-bit flags are considered aliases - multi_bit_total |= flag_value - enum_class._flag_mask_ = single_bit_total - # # set correct __iter__ member_list = [m._value_ for m in enum_class] if member_list != sorted(member_list): @@ -1303,8 +1296,8 @@ def _reduce_ex_by_global_name(self, proto): class FlagBoundary(StrEnum): """ control how out of range values are handled - "strict" -> error is raised - "conform" -> extra bits are discarded [default for Flag] + "strict" -> error is raised [default for Flag] + "conform" -> extra bits are discarded "eject" -> lose flag status "keep" -> keep flag status and all bits [default for IntFlag] """ @@ -1315,7 +1308,7 @@ class FlagBoundary(StrEnum): STRICT, CONFORM, EJECT, KEEP = FlagBoundary -class Flag(Enum, boundary=CONFORM): +class Flag(Enum, boundary=STRICT): """ Support for flags """ @@ -1394,6 +1387,7 @@ def _missing_(cls, value): # - value must not include any skipped flags (e.g. if bit 2 is not # defined, then 0d10 is invalid) flag_mask = cls._flag_mask_ + singles_mask = cls._singles_mask_ all_bits = cls._all_bits_ neg_value = None if ( @@ -1425,7 +1419,8 @@ def _missing_(cls, value): value = all_bits + 1 + value # get members and unknown unknown = value & ~flag_mask - member_value = value & flag_mask + aliases = value & ~singles_mask + member_value = value & singles_mask if unknown and cls._boundary_ is not KEEP: raise ValueError( '%s(%r) --> unknown values %r [%s]' @@ -1439,11 +1434,25 @@ def _missing_(cls, value): pseudo_member = cls._member_type_.__new__(cls, value) if not hasattr(pseudo_member, '_value_'): pseudo_member._value_ = value - if member_value: - pseudo_member._name_ = '|'.join([ - m._name_ for m in cls._iter_member_(member_value) - ]) - if unknown: + if member_value or aliases: + members = [] + combined_value = 0 + for m in cls._iter_member_(member_value): + members.append(m) + combined_value |= m._value_ + if aliases: + value = member_value | aliases + for n, pm in cls._member_map_.items(): + if pm not in members and pm._value_ and pm._value_ & value == pm._value_: + members.append(pm) + combined_value |= pm._value_ + unknown = value ^ combined_value + pseudo_member._name_ = '|'.join([m._name_ for m in members]) + if not combined_value: + pseudo_member._name_ = None + elif unknown and cls._boundary_ is STRICT: + raise ValueError('%r: no members with value %r' % (cls, unknown)) + elif unknown: pseudo_member._name_ += '|%s' % cls._numeric_repr_(unknown) else: pseudo_member._name_ = None @@ -1675,6 +1684,7 @@ def convert_class(cls): body['_boundary_'] = boundary or etype._boundary_ body['_flag_mask_'] = None body['_all_bits_'] = None + body['_singles_mask_'] = None body['_inverted_'] = None body['__or__'] = Flag.__or__ body['__xor__'] = Flag.__xor__ @@ -1750,7 +1760,8 @@ def convert_class(cls): else: multi_bits |= value gnv_last_values.append(value) - enum_class._flag_mask_ = single_bits + enum_class._flag_mask_ = single_bits | multi_bits + enum_class._singles_mask_ = single_bits enum_class._all_bits_ = 2 ** ((single_bits|multi_bits).bit_length()) - 1 # set correct __iter__ member_list = [m._value_ for m in enum_class] diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index e4151bf9e6d9..89294e95df2a 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -2873,6 +2873,8 @@ def __new__(cls, c): # a = ord('a') # + self.assertEqual(FlagFromChar._all_bits_, 316912650057057350374175801343) + self.assertEqual(FlagFromChar._flag_mask_, 158456325028528675187087900672) self.assertEqual(FlagFromChar.a, 158456325028528675187087900672) self.assertEqual(FlagFromChar.a|1, 158456325028528675187087900673) # @@ -2887,6 +2889,8 @@ def __new__(cls, c): a = ord('a') z = 1 # + self.assertEqual(FlagFromChar._all_bits_, 316912650057057350374175801343) + self.assertEqual(FlagFromChar._flag_mask_, 158456325028528675187087900674) self.assertEqual(FlagFromChar.a.value, 158456325028528675187087900672) self.assertEqual((FlagFromChar.a|FlagFromChar.z).value, 158456325028528675187087900674) # @@ -2900,6 +2904,8 @@ def __new__(cls, c): # a = ord('a') # + self.assertEqual(FlagFromChar._all_bits_, 316912650057057350374175801343) + self.assertEqual(FlagFromChar._flag_mask_, 158456325028528675187087900672) self.assertEqual(FlagFromChar.a, 158456325028528675187087900672) self.assertEqual(FlagFromChar.a|1, 158456325028528675187087900673) @@ -3077,18 +3083,18 @@ def test_bool(self): self.assertEqual(bool(f.value), bool(f)) def test_boundary(self): - self.assertIs(enum.Flag._boundary_, CONFORM) - class Iron(Flag, boundary=STRICT): + self.assertIs(enum.Flag._boundary_, STRICT) + class Iron(Flag, boundary=CONFORM): ONE = 1 TWO = 2 EIGHT = 8 - self.assertIs(Iron._boundary_, STRICT) + self.assertIs(Iron._boundary_, CONFORM) # - class Water(Flag, boundary=CONFORM): + class Water(Flag, boundary=STRICT): ONE = 1 TWO = 2 EIGHT = 8 - self.assertIs(Water._boundary_, CONFORM) + self.assertIs(Water._boundary_, STRICT) # class Space(Flag, boundary=EJECT): ONE = 1 @@ -3101,10 +3107,10 @@ class Bizarre(Flag, boundary=KEEP): c = 4 d = 6 # - self.assertRaisesRegex(ValueError, 'invalid value 7', Iron, 7) + self.assertRaisesRegex(ValueError, 'invalid value 7', Water, 7) # - self.assertIs(Water(7), Water.ONE|Water.TWO) - self.assertIs(Water(~9), Water.TWO) + self.assertIs(Iron(7), Iron.ONE|Iron.TWO) + self.assertIs(Iron(~9), Iron.TWO) # self.assertEqual(Space(7), 7) self.assertTrue(type(Space(7)) is int) @@ -3112,6 +3118,31 @@ class Bizarre(Flag, boundary=KEEP): self.assertEqual(list(Bizarre), [Bizarre.c]) self.assertIs(Bizarre(3), Bizarre.b) self.assertIs(Bizarre(6), Bizarre.d) + # + class SkipFlag(enum.Flag): + A = 1 + B = 2 + C = 4 | B + # + self.assertTrue(SkipFlag.C in (SkipFlag.A|SkipFlag.C)) + self.assertRaisesRegex(ValueError, 'SkipFlag.. invalid value 42', SkipFlag, 42) + # + class SkipIntFlag(enum.IntFlag): + A = 1 + B = 2 + C = 4 | B + # + self.assertTrue(SkipIntFlag.C in (SkipIntFlag.A|SkipIntFlag.C)) + self.assertEqual(SkipIntFlag(42).value, 42) + # + class MethodHint(Flag): + HiddenText = 0x10 + DigitsOnly = 0x01 + LettersOnly = 0x02 + OnlyMask = 0x0f + # + self.assertEqual(str(MethodHint.HiddenText|MethodHint.OnlyMask), 'MethodHint.HiddenText|DigitsOnly|LettersOnly|OnlyMask') + def test_iter(self): Color = self.Color diff --git a/Misc/NEWS.d/next/Library/2023-04-12-17-59-55.gh-issue-103365.UBEE0U.rst b/Misc/NEWS.d/next/Library/2023-04-12-17-59-55.gh-issue-103365.UBEE0U.rst new file mode 100644 index 000000000000..4d69f6f6fff7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-12-17-59-55.gh-issue-103365.UBEE0U.rst @@ -0,0 +1 @@ +Set default Flag boundary to ``STRICT`` and fix bitwise operations. From webhook-mailer at python.org Thu Apr 13 11:31:11 2023 From: webhook-mailer at python.org (ethanfurman) Date: Thu, 13 Apr 2023 15:31:11 -0000 Subject: [Python-checkins] gh-103479: [Enum] require __new__ to be considered a data type (GH-103495) Message-ID: https://github.com/python/cpython/commit/a6f95941a3d686707fb38e0f37758e666f25e180 commit: a6f95941a3d686707fb38e0f37758e666f25e180 branch: main author: Ethan Furman committer: ethanfurman date: 2023-04-13T08:31:03-07:00 summary: gh-103479: [Enum] require __new__ to be considered a data type (GH-103495) a mixin must either have a __new__ method, or be a dataclass, to be interpreted as a data-type files: M Doc/howto/enum.rst M Lib/enum.py M Lib/test/test_enum.py diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst index 9390faded2fb..56391a026cf8 100644 --- a/Doc/howto/enum.rst +++ b/Doc/howto/enum.rst @@ -865,17 +865,19 @@ Some rules: 4. When another data type is mixed in, the :attr:`value` attribute is *not the same* as the enum member itself, although it is equivalent and will compare equal. -5. %-style formatting: ``%s`` and ``%r`` call the :class:`Enum` class's +5. A ``data type`` is a mixin that defines :meth:`__new__`, or a + :class:`~dataclasses.dataclass` +6. %-style formatting: ``%s`` and ``%r`` call the :class:`Enum` class's :meth:`__str__` and :meth:`__repr__` respectively; other codes (such as ``%i`` or ``%h`` for IntEnum) treat the enum member as its mixed-in type. -6. :ref:`Formatted string literals `, :meth:`str.format`, +7. :ref:`Formatted string literals `, :meth:`str.format`, and :func:`format` will use the enum's :meth:`__str__` method. .. note:: Because :class:`IntEnum`, :class:`IntFlag`, and :class:`StrEnum` are designed to be drop-in replacements for existing constants, their - :meth:`__str__` method has been reset to their data types + :meth:`__str__` method has been reset to their data types' :meth:`__str__` method. When to use :meth:`__new__` vs. :meth:`__init__` diff --git a/Lib/enum.py b/Lib/enum.py index 432d7456b4b9..e9f224a303d3 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -967,6 +967,7 @@ def _find_data_repr_(mcls, class_name, bases): @classmethod def _find_data_type_(mcls, class_name, bases): + # a datatype has a __new__ method, or a __dataclass_fields__ attribute data_types = set() base_chain = set() for chain in bases: @@ -979,7 +980,7 @@ def _find_data_type_(mcls, class_name, bases): if base._member_type_ is not object: data_types.add(base._member_type_) break - elif '__new__' in base.__dict__ or '__init__' in base.__dict__: + elif '__new__' in base.__dict__ or '__dataclass_fields__' in base.__dict__: data_types.add(candidate or base) break else: diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 89294e95df2a..e9dfcf8586a8 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -2737,10 +2737,10 @@ def __repr__(self): return 'ha hah!' class Entries(Foo, Enum): ENTRY1 = 1 + self.assertEqual(repr(Entries.ENTRY1), '') + self.assertTrue(Entries.ENTRY1.value == Foo(1), Entries.ENTRY1.value) self.assertTrue(isinstance(Entries.ENTRY1, Foo)) self.assertTrue(Entries._member_type_ is Foo, Entries._member_type_) - self.assertTrue(Entries.ENTRY1.value == Foo(1), Entries.ENTRY1.value) - self.assertEqual(repr(Entries.ENTRY1), '') # # check auto-generated dataclass __repr__ is not used # @@ -2787,8 +2787,7 @@ class Creature(CreatureDataMixin, Enum): DOG = ('medium', 4) self.assertRegex(repr(Creature.DOG), "") - def test_repr_with_init_data_type_mixin(self): - # non-data_type is a mixin that doesn't define __new__ + def test_repr_with_init_mixin(self): class Foo: def __init__(self, a): self.a = a @@ -2797,9 +2796,9 @@ def __repr__(self): class Entries(Foo, Enum): ENTRY1 = 1 # - self.assertEqual(repr(Entries.ENTRY1), '') + self.assertEqual(repr(Entries.ENTRY1), 'Foo(a=1)') - def test_repr_and_str_with_non_data_type_mixin(self): + def test_repr_and_str_with_no_init_mixin(self): # non-data_type is a mixin that doesn't define __new__ class Foo: def __repr__(self): @@ -2911,6 +2910,8 @@ def __new__(cls, c): def test_init_exception(self): class Base: + def __new__(cls, *args): + return object.__new__(cls) def __init__(self, x): raise ValueError("I don't like", x) with self.assertRaises(TypeError): From webhook-mailer at python.org Thu Apr 13 11:56:02 2023 From: webhook-mailer at python.org (miss-islington) Date: Thu, 13 Apr 2023 15:56:02 -0000 Subject: [Python-checkins] gh-103365: [Enum] STRICT boundary corrections (GH-103494) Message-ID: https://github.com/python/cpython/commit/804a973d8e5fd2728aeef268f3e577d2c0b05baa commit: 804a973d8e5fd2728aeef268f3e577d2c0b05baa branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-13T08:55:53-07:00 summary: gh-103365: [Enum] STRICT boundary corrections (GH-103494) STRICT boundary: - fix bitwise operations - make default for Flag (cherry picked from commit 2194071540313e2bbdc7214d77453b9ce3034a5c) Co-authored-by: Ethan Furman files: A Misc/NEWS.d/next/Library/2023-04-12-17-59-55.gh-issue-103365.UBEE0U.rst M Doc/library/enum.rst M Lib/enum.py M Lib/test/test_enum.py diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index 34df5c511bf4..27400cf993c0 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -692,7 +692,8 @@ Data Types .. attribute:: STRICT - Out-of-range values cause a :exc:`ValueError` to be raised:: + Out-of-range values cause a :exc:`ValueError` to be raised. This is the + default for :class:`Flag`:: >>> from enum import Flag, STRICT, auto >>> class StrictFlag(Flag, boundary=STRICT): @@ -709,7 +710,7 @@ Data Types .. attribute:: CONFORM Out-of-range values have invalid values removed, leaving a valid *Flag* - value. This is the default for :class:`Flag`:: + value:: >>> from enum import Flag, CONFORM, auto >>> class ConformFlag(Flag, boundary=CONFORM): diff --git a/Lib/enum.py b/Lib/enum.py index 84ae339d0d40..a884b50541e5 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -273,6 +273,13 @@ def __set_name__(self, enum_class, member_name): enum_member.__objclass__ = enum_class enum_member.__init__(*args) enum_member._sort_order_ = len(enum_class._member_names_) + + if Flag is not None and issubclass(enum_class, Flag): + enum_class._flag_mask_ |= value + if _is_single_bit(value): + enum_class._singles_mask_ |= value + enum_class._all_bits_ = 2 ** ((enum_class._flag_mask_).bit_length()) - 1 + # If another member with the same value was already defined, the # new member becomes an alias to the existing one. try: @@ -525,12 +532,8 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k classdict['_use_args_'] = use_args # # convert future enum members into temporary _proto_members - # and record integer values in case this will be a Flag - flag_mask = 0 for name in member_names: value = classdict[name] - if isinstance(value, int): - flag_mask |= value classdict[name] = _proto_member(value) # # house-keeping structures @@ -547,8 +550,9 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k boundary or getattr(first_enum, '_boundary_', None) ) - classdict['_flag_mask_'] = flag_mask - classdict['_all_bits_'] = 2 ** ((flag_mask).bit_length()) - 1 + classdict['_flag_mask_'] = 0 + classdict['_singles_mask_'] = 0 + classdict['_all_bits_'] = 0 classdict['_inverted_'] = None try: exc = None @@ -637,21 +641,10 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k ): delattr(enum_class, '_boundary_') delattr(enum_class, '_flag_mask_') + delattr(enum_class, '_singles_mask_') delattr(enum_class, '_all_bits_') delattr(enum_class, '_inverted_') elif Flag is not None and issubclass(enum_class, Flag): - # ensure _all_bits_ is correct and there are no missing flags - single_bit_total = 0 - multi_bit_total = 0 - for flag in enum_class._member_map_.values(): - flag_value = flag._value_ - if _is_single_bit(flag_value): - single_bit_total |= flag_value - else: - # multi-bit flags are considered aliases - multi_bit_total |= flag_value - enum_class._flag_mask_ = single_bit_total - # # set correct __iter__ member_list = [m._value_ for m in enum_class] if member_list != sorted(member_list): @@ -1303,8 +1296,8 @@ def _reduce_ex_by_global_name(self, proto): class FlagBoundary(StrEnum): """ control how out of range values are handled - "strict" -> error is raised - "conform" -> extra bits are discarded [default for Flag] + "strict" -> error is raised [default for Flag] + "conform" -> extra bits are discarded "eject" -> lose flag status "keep" -> keep flag status and all bits [default for IntFlag] """ @@ -1315,7 +1308,7 @@ class FlagBoundary(StrEnum): STRICT, CONFORM, EJECT, KEEP = FlagBoundary -class Flag(Enum, boundary=CONFORM): +class Flag(Enum, boundary=STRICT): """ Support for flags """ @@ -1393,6 +1386,7 @@ def _missing_(cls, value): # - value must not include any skipped flags (e.g. if bit 2 is not # defined, then 0d10 is invalid) flag_mask = cls._flag_mask_ + singles_mask = cls._singles_mask_ all_bits = cls._all_bits_ neg_value = None if ( @@ -1424,7 +1418,8 @@ def _missing_(cls, value): value = all_bits + 1 + value # get members and unknown unknown = value & ~flag_mask - member_value = value & flag_mask + aliases = value & ~singles_mask + member_value = value & singles_mask if unknown and cls._boundary_ is not KEEP: raise ValueError( '%s(%r) --> unknown values %r [%s]' @@ -1438,11 +1433,25 @@ def _missing_(cls, value): pseudo_member = cls._member_type_.__new__(cls, value) if not hasattr(pseudo_member, '_value_'): pseudo_member._value_ = value - if member_value: - pseudo_member._name_ = '|'.join([ - m._name_ for m in cls._iter_member_(member_value) - ]) - if unknown: + if member_value or aliases: + members = [] + combined_value = 0 + for m in cls._iter_member_(member_value): + members.append(m) + combined_value |= m._value_ + if aliases: + value = member_value | aliases + for n, pm in cls._member_map_.items(): + if pm not in members and pm._value_ and pm._value_ & value == pm._value_: + members.append(pm) + combined_value |= pm._value_ + unknown = value ^ combined_value + pseudo_member._name_ = '|'.join([m._name_ for m in members]) + if not combined_value: + pseudo_member._name_ = None + elif unknown and cls._boundary_ is STRICT: + raise ValueError('%r: no members with value %r' % (cls, unknown)) + elif unknown: pseudo_member._name_ += '|%s' % cls._numeric_repr_(unknown) else: pseudo_member._name_ = None @@ -1671,6 +1680,7 @@ def convert_class(cls): body['_boundary_'] = boundary or etype._boundary_ body['_flag_mask_'] = None body['_all_bits_'] = None + body['_singles_mask_'] = None body['_inverted_'] = None body['__or__'] = Flag.__or__ body['__xor__'] = Flag.__xor__ @@ -1743,7 +1753,8 @@ def convert_class(cls): else: multi_bits |= value gnv_last_values.append(value) - enum_class._flag_mask_ = single_bits + enum_class._flag_mask_ = single_bits | multi_bits + enum_class._singles_mask_ = single_bits enum_class._all_bits_ = 2 ** ((single_bits|multi_bits).bit_length()) - 1 # set correct __iter__ member_list = [m._value_ for m in enum_class] diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 51dd66bea0c4..d3b4832e3406 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -2758,6 +2758,8 @@ def __new__(cls, c): # a = ord('a') # + self.assertEqual(FlagFromChar._all_bits_, 316912650057057350374175801343) + self.assertEqual(FlagFromChar._flag_mask_, 158456325028528675187087900672) self.assertEqual(FlagFromChar.a, 158456325028528675187087900672) self.assertEqual(FlagFromChar.a|1, 158456325028528675187087900673) # @@ -2772,6 +2774,8 @@ def __new__(cls, c): a = ord('a') z = 1 # + self.assertEqual(FlagFromChar._all_bits_, 316912650057057350374175801343) + self.assertEqual(FlagFromChar._flag_mask_, 158456325028528675187087900674) self.assertEqual(FlagFromChar.a.value, 158456325028528675187087900672) self.assertEqual((FlagFromChar.a|FlagFromChar.z).value, 158456325028528675187087900674) # @@ -2785,6 +2789,8 @@ def __new__(cls, c): # a = ord('a') # + self.assertEqual(FlagFromChar._all_bits_, 316912650057057350374175801343) + self.assertEqual(FlagFromChar._flag_mask_, 158456325028528675187087900672) self.assertEqual(FlagFromChar.a, 158456325028528675187087900672) self.assertEqual(FlagFromChar.a|1, 158456325028528675187087900673) @@ -2962,18 +2968,18 @@ def test_bool(self): self.assertEqual(bool(f.value), bool(f)) def test_boundary(self): - self.assertIs(enum.Flag._boundary_, CONFORM) - class Iron(Flag, boundary=STRICT): + self.assertIs(enum.Flag._boundary_, STRICT) + class Iron(Flag, boundary=CONFORM): ONE = 1 TWO = 2 EIGHT = 8 - self.assertIs(Iron._boundary_, STRICT) + self.assertIs(Iron._boundary_, CONFORM) # - class Water(Flag, boundary=CONFORM): + class Water(Flag, boundary=STRICT): ONE = 1 TWO = 2 EIGHT = 8 - self.assertIs(Water._boundary_, CONFORM) + self.assertIs(Water._boundary_, STRICT) # class Space(Flag, boundary=EJECT): ONE = 1 @@ -2986,10 +2992,10 @@ class Bizarre(Flag, boundary=KEEP): c = 4 d = 6 # - self.assertRaisesRegex(ValueError, 'invalid value 7', Iron, 7) + self.assertRaisesRegex(ValueError, 'invalid value 7', Water, 7) # - self.assertIs(Water(7), Water.ONE|Water.TWO) - self.assertIs(Water(~9), Water.TWO) + self.assertIs(Iron(7), Iron.ONE|Iron.TWO) + self.assertIs(Iron(~9), Iron.TWO) # self.assertEqual(Space(7), 7) self.assertTrue(type(Space(7)) is int) @@ -2997,6 +3003,31 @@ class Bizarre(Flag, boundary=KEEP): self.assertEqual(list(Bizarre), [Bizarre.c]) self.assertIs(Bizarre(3), Bizarre.b) self.assertIs(Bizarre(6), Bizarre.d) + # + class SkipFlag(enum.Flag): + A = 1 + B = 2 + C = 4 | B + # + self.assertTrue(SkipFlag.C in (SkipFlag.A|SkipFlag.C)) + self.assertRaisesRegex(ValueError, 'SkipFlag.. invalid value 42', SkipFlag, 42) + # + class SkipIntFlag(enum.IntFlag): + A = 1 + B = 2 + C = 4 | B + # + self.assertTrue(SkipIntFlag.C in (SkipIntFlag.A|SkipIntFlag.C)) + self.assertEqual(SkipIntFlag(42).value, 42) + # + class MethodHint(Flag): + HiddenText = 0x10 + DigitsOnly = 0x01 + LettersOnly = 0x02 + OnlyMask = 0x0f + # + self.assertEqual(str(MethodHint.HiddenText|MethodHint.OnlyMask), 'MethodHint.HiddenText|DigitsOnly|LettersOnly|OnlyMask') + def test_iter(self): Color = self.Color diff --git a/Misc/NEWS.d/next/Library/2023-04-12-17-59-55.gh-issue-103365.UBEE0U.rst b/Misc/NEWS.d/next/Library/2023-04-12-17-59-55.gh-issue-103365.UBEE0U.rst new file mode 100644 index 000000000000..4d69f6f6fff7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-12-17-59-55.gh-issue-103365.UBEE0U.rst @@ -0,0 +1 @@ +Set default Flag boundary to ``STRICT`` and fix bitwise operations. From webhook-mailer at python.org Thu Apr 13 13:45:43 2023 From: webhook-mailer at python.org (markshannon) Date: Thu, 13 Apr 2023 17:45:43 -0000 Subject: [Python-checkins] Fix unused functions warnings in instrumentation.c (GH-103515) Message-ID: https://github.com/python/cpython/commit/7b95d23591f605fc05d4820f83fef8fbf1552729 commit: 7b95d23591f605fc05d4820f83fef8fbf1552729 branch: main author: Benjamin Peterson committer: markshannon date: 2023-04-13T18:45:03+01:00 summary: Fix unused functions warnings in instrumentation.c (GH-103515) files: M Python/instrumentation.c diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 8dc8b01fcb04..853e8a10e814 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -125,6 +125,7 @@ is_instrumented(int opcode) { return opcode >= MIN_INSTRUMENTED_OPCODE; } +#ifndef NDEBUG static inline bool monitors_equals(_Py_Monitors a, _Py_Monitors b) { @@ -135,6 +136,7 @@ monitors_equals(_Py_Monitors a, _Py_Monitors b) } return true; } +#endif static inline _Py_Monitors monitors_sub(_Py_Monitors a, _Py_Monitors b) @@ -146,6 +148,7 @@ monitors_sub(_Py_Monitors a, _Py_Monitors b) return res; } +#ifndef NDEBUG static inline _Py_Monitors monitors_and(_Py_Monitors a, _Py_Monitors b) { @@ -155,6 +158,7 @@ monitors_and(_Py_Monitors a, _Py_Monitors b) } return res; } +#endif static inline _Py_Monitors monitors_or(_Py_Monitors a, _Py_Monitors b) From webhook-mailer at python.org Thu Apr 13 15:04:14 2023 From: webhook-mailer at python.org (ethanfurman) Date: Thu, 13 Apr 2023 19:04:14 -0000 Subject: [Python-checkins] [3.11] gh-103479: [Enum] require __new__ to be considered a data type (GH-103495) (GH-103514) Message-ID: https://github.com/python/cpython/commit/3b929a7b321dae113593d81caf47c4f08890c615 commit: 3b929a7b321dae113593d81caf47c4f08890c615 branch: 3.11 author: Ethan Furman committer: ethanfurman date: 2023-04-13T12:04:06-07:00 summary: [3.11] gh-103479: [Enum] require __new__ to be considered a data type (GH-103495) (GH-103514) a mixin must either have a __new__ method, or be a dataclass, to be interpreted as a data-type; an __init__ method is not enough (restores pre-3.11 behavior for non-dataclasses). (cherry picked from commit a6f95941a3d686707fb38e0f37758e666f25e180) Co-authored-by: Ethan Furman files: M Doc/howto/enum.rst M Lib/enum.py M Lib/test/test_enum.py diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst index 32310692fe56..55f0dfb4c48c 100644 --- a/Doc/howto/enum.rst +++ b/Doc/howto/enum.rst @@ -837,17 +837,18 @@ Some rules: 4. When another data type is mixed in, the :attr:`value` attribute is *not the same* as the enum member itself, although it is equivalent and will compare equal. -5. %-style formatting: ``%s`` and ``%r`` call the :class:`Enum` class's +5. A ``data type`` is a mixin that defines :meth:`__new__`. +6. %-style formatting: ``%s`` and ``%r`` call the :class:`Enum` class's :meth:`__str__` and :meth:`__repr__` respectively; other codes (such as ``%i`` or ``%h`` for IntEnum) treat the enum member as its mixed-in type. -6. :ref:`Formatted string literals `, :meth:`str.format`, +7. :ref:`Formatted string literals `, :meth:`str.format`, and :func:`format` will use the enum's :meth:`__str__` method. .. note:: Because :class:`IntEnum`, :class:`IntFlag`, and :class:`StrEnum` are designed to be drop-in replacements for existing constants, their - :meth:`__str__` method has been reset to their data types + :meth:`__str__` method has been reset to their data types' :meth:`__str__` method. When to use :meth:`__new__` vs. :meth:`__init__` diff --git a/Lib/enum.py b/Lib/enum.py index a884b50541e5..26e5c50bf856 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -974,6 +974,7 @@ def _find_data_repr_(mcls, class_name, bases): @classmethod def _find_data_type_(mcls, class_name, bases): + # a datatype has a __new__ method data_types = set() base_chain = set() for chain in bases: @@ -986,7 +987,7 @@ def _find_data_type_(mcls, class_name, bases): if base._member_type_ is not object: data_types.add(base._member_type_) break - elif '__new__' in base.__dict__ or '__init__' in base.__dict__: + elif '__new__' in base.__dict__ or '__dataclass_fields__' in base.__dict__: if isinstance(base, EnumType): continue data_types.add(candidate or base) diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index d3b4832e3406..188e1a174756 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -2672,19 +2672,18 @@ class Entries(Foo, Enum): self.assertTrue(Entries.ENTRY1.value == Foo(1), Entries.ENTRY1.value) self.assertEqual(repr(Entries.ENTRY1), '') - def test_repr_with_init_data_type_mixin(self): - # non-data_type is a mixin that doesn't define __new__ + def test_repr_with_init_mixin(self): class Foo: def __init__(self, a): self.a = a def __repr__(self): - return f'Foo(a={self.a!r})' + return 'Foo(a=%r)' % self._value_ class Entries(Foo, Enum): ENTRY1 = 1 # - self.assertEqual(repr(Entries.ENTRY1), '') + self.assertEqual(repr(Entries.ENTRY1), 'Foo(a=1)') - def test_repr_and_str_with_non_data_type_mixin(self): + def test_repr_and_str_with_no_init_mixin(self): # non-data_type is a mixin that doesn't define __new__ class Foo: def __repr__(self): @@ -2796,6 +2795,8 @@ def __new__(cls, c): def test_init_exception(self): class Base: + def __new__(cls, *args): + return object.__new__(cls) def __init__(self, x): raise ValueError("I don't like", x) with self.assertRaises(TypeError): From webhook-mailer at python.org Thu Apr 13 23:08:31 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Fri, 14 Apr 2023 03:08:31 -0000 Subject: [Python-checkins] Proofread howto/perf_profiling.rst (#103530) Message-ID: https://github.com/python/cpython/commit/a3d313a9e2d894f301557c18788aa1eec16c507c commit: a3d313a9e2d894f301557c18788aa1eec16c507c branch: main author: Boris Verkhovskiy committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-04-13T20:07:49-07:00 summary: Proofread howto/perf_profiling.rst (#103530) files: M Doc/howto/perf_profiling.rst diff --git a/Doc/howto/perf_profiling.rst b/Doc/howto/perf_profiling.rst index ad2eb7b4d58a..6af5536166f5 100644 --- a/Doc/howto/perf_profiling.rst +++ b/Doc/howto/perf_profiling.rst @@ -15,9 +15,9 @@ information about the performance of your application. that aid with the analysis of the data that it produces. The main problem with using the ``perf`` profiler with Python applications is that -``perf`` only allows to get information about native symbols, this is, the names of -the functions and procedures written in C. This means that the names and file names -of the Python functions in your code will not appear in the output of the ``perf``. +``perf`` only gets information about native symbols, that is, the names of +functions and procedures written in C. This means that the names and file names +of Python functions in your code will not appear in the output of ``perf``. Since Python 3.12, the interpreter can run in a special mode that allows Python functions to appear in the output of the ``perf`` profiler. When this mode is @@ -28,8 +28,8 @@ relationship between this piece of code and the associated Python function using .. note:: - Support for the ``perf`` profiler is only currently available for Linux on - selected architectures. Check the output of the configure build step or + Support for the ``perf`` profiler is currently only available for Linux on + select architectures. Check the output of the ``configure`` build step or check the output of ``python -m sysconfig | grep HAVE_PERF_TRAMPOLINE`` to see if your system is supported. @@ -52,11 +52,11 @@ For example, consider the following script: if __name__ == "__main__": baz(1000000) -We can run ``perf`` to sample CPU stack traces at 9999 Hertz:: +We can run ``perf`` to sample CPU stack traces at 9999 hertz:: $ perf record -F 9999 -g -o perf.data python my_script.py -Then we can use ``perf`` report to analyze the data: +Then we can use ``perf report`` to analyze the data: .. code-block:: shell-session @@ -97,7 +97,7 @@ Then we can use ``perf`` report to analyze the data: | | | | | |--2.97%--_PyObject_Malloc ... -As you can see here, the Python functions are not shown in the output, only ``_Py_Eval_EvalFrameDefault`` appears +As you can see, the Python functions are not shown in the output, only ``_Py_Eval_EvalFrameDefault`` (the function that evaluates the Python bytecode) shows up. Unfortunately that's not very useful because all Python functions use the same C function to evaluate bytecode so we cannot know which Python function corresponds to which bytecode-evaluating function. @@ -151,7 +151,7 @@ Instead, if we run the same experiment with ``perf`` support enabled we get: How to enable ``perf`` profiling support ---------------------------------------- -``perf`` profiling support can either be enabled from the start using +``perf`` profiling support can be enabled either from the start using the environment variable :envvar:`PYTHONPERFSUPPORT` or the :option:`-X perf <-X>` option, or dynamically using :func:`sys.activate_stack_trampoline` and @@ -192,7 +192,7 @@ Example, using the :mod:`sys` APIs in file :file:`example.py`: How to obtain the best results ------------------------------ -For the best results, Python should be compiled with +For best results, Python should be compiled with ``CFLAGS="-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer"`` as this allows profilers to unwind using only the frame pointer and not on DWARF debug information. This is because as the code that is interposed to allow ``perf`` From webhook-mailer at python.org Fri Apr 14 03:07:10 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 14 Apr 2023 07:07:10 -0000 Subject: [Python-checkins] gh-103406: Modernize pos-only arguments usage in `test_signature` (#103407) Message-ID: https://github.com/python/cpython/commit/756978117698eeac3af270db25d22599e681bcb3 commit: 756978117698eeac3af270db25d22599e681bcb3 branch: main author: Nikita Sobolev committer: JelleZijlstra date: 2023-04-14T00:06:31-07:00 summary: gh-103406: Modernize pos-only arguments usage in `test_signature` (#103407) files: M Lib/test/test_inspect.py diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 3a3646f1861e..cfdb992654c2 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -3044,14 +3044,9 @@ def foo(a=1, b=2, c=3): self.assertEqual(_foo(*ba.args, **ba.kwargs), (12, 10, 20)) - def foo(a, b, c, d, **kwargs): + def foo(a, b, /, c, d, **kwargs): pass sig = inspect.signature(foo) - params = sig.parameters.copy() - params['a'] = params['a'].replace(kind=Parameter.POSITIONAL_ONLY) - params['b'] = params['b'].replace(kind=Parameter.POSITIONAL_ONLY) - foo.__signature__ = inspect.Signature(params.values()) - sig = inspect.signature(foo) self.assertEqual(str(sig), '(a, b, /, c, d, **kwargs)') self.assertEqual(self.signature(partial(foo, 1)), @@ -3556,14 +3551,9 @@ def test_signature_str_positional_only(self): P = inspect.Parameter S = inspect.Signature - def test(a_po, *, b, **kwargs): + def test(a_po, /, *, b, **kwargs): return a_po, kwargs - sig = inspect.signature(test) - new_params = list(sig.parameters.values()) - new_params[0] = new_params[0].replace(kind=P.POSITIONAL_ONLY) - test.__signature__ = sig.replace(parameters=new_params) - self.assertEqual(str(inspect.signature(test)), '(a_po, /, *, b, **kwargs)') @@ -3593,6 +3583,14 @@ def test() -> 42: self.assertEqual(sig.return_annotation, 42) self.assertEqual(sig, inspect.signature(test)) + def test_signature_replaced(self): + def test(): + pass + + spam_param = inspect.Parameter('spam', inspect.Parameter.POSITIONAL_ONLY) + sig = test.__signature__ = inspect.Signature(parameters=(spam_param,)) + self.assertEqual(sig, inspect.signature(test)) + def test_signature_on_mangled_parameters(self): class Spam: def foo(self, __p1:1=2, *, __p2:2=3): @@ -4157,16 +4155,9 @@ def test(a, *args, b, z=100, **kwargs): def test_signature_bind_positional_only(self): P = inspect.Parameter - def test(a_po, b_po, c_po=3, foo=42, *, bar=50, **kwargs): + def test(a_po, b_po, c_po=3, /, foo=42, *, bar=50, **kwargs): return a_po, b_po, c_po, foo, bar, kwargs - sig = inspect.signature(test) - new_params = collections.OrderedDict(tuple(sig.parameters.items())) - for name in ('a_po', 'b_po', 'c_po'): - new_params[name] = new_params[name].replace(kind=P.POSITIONAL_ONLY) - new_sig = sig.replace(parameters=new_params.values()) - test.__signature__ = new_sig - self.assertEqual(self.call(test, 1, 2, 4, 5, bar=6), (1, 2, 4, 5, 6, {})) From webhook-mailer at python.org Fri Apr 14 03:30:52 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 14 Apr 2023 07:30:52 -0000 Subject: [Python-checkins] gh-103406: Modernize pos-only arguments usage in `test_signature` (GH-103407) Message-ID: https://github.com/python/cpython/commit/2e0ead5f22bb7699d70f1dfb6d1eadff124f2688 commit: 2e0ead5f22bb7699d70f1dfb6d1eadff124f2688 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-14T00:30:38-07:00 summary: gh-103406: Modernize pos-only arguments usage in `test_signature` (GH-103407) (cherry picked from commit 756978117698eeac3af270db25d22599e681bcb3) Co-authored-by: Nikita Sobolev files: M Lib/test/test_inspect.py diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index c50486003a4d..a6507c7386a2 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -2882,14 +2882,9 @@ def foo(a=1, b=2, c=3): self.assertEqual(_foo(*ba.args, **ba.kwargs), (12, 10, 20)) - def foo(a, b, c, d, **kwargs): + def foo(a, b, /, c, d, **kwargs): pass sig = inspect.signature(foo) - params = sig.parameters.copy() - params['a'] = params['a'].replace(kind=Parameter.POSITIONAL_ONLY) - params['b'] = params['b'].replace(kind=Parameter.POSITIONAL_ONLY) - foo.__signature__ = inspect.Signature(params.values()) - sig = inspect.signature(foo) self.assertEqual(str(sig), '(a, b, /, c, d, **kwargs)') self.assertEqual(self.signature(partial(foo, 1)), @@ -3394,14 +3389,9 @@ def test_signature_str_positional_only(self): P = inspect.Parameter S = inspect.Signature - def test(a_po, *, b, **kwargs): + def test(a_po, /, *, b, **kwargs): return a_po, kwargs - sig = inspect.signature(test) - new_params = list(sig.parameters.values()) - new_params[0] = new_params[0].replace(kind=P.POSITIONAL_ONLY) - test.__signature__ = sig.replace(parameters=new_params) - self.assertEqual(str(inspect.signature(test)), '(a_po, /, *, b, **kwargs)') @@ -3431,6 +3421,14 @@ def test() -> 42: self.assertEqual(sig.return_annotation, 42) self.assertEqual(sig, inspect.signature(test)) + def test_signature_replaced(self): + def test(): + pass + + spam_param = inspect.Parameter('spam', inspect.Parameter.POSITIONAL_ONLY) + sig = test.__signature__ = inspect.Signature(parameters=(spam_param,)) + self.assertEqual(sig, inspect.signature(test)) + def test_signature_on_mangled_parameters(self): class Spam: def foo(self, __p1:1=2, *, __p2:2=3): @@ -3962,16 +3960,9 @@ def test(a, *args, b, z=100, **kwargs): def test_signature_bind_positional_only(self): P = inspect.Parameter - def test(a_po, b_po, c_po=3, foo=42, *, bar=50, **kwargs): + def test(a_po, b_po, c_po=3, /, foo=42, *, bar=50, **kwargs): return a_po, b_po, c_po, foo, bar, kwargs - sig = inspect.signature(test) - new_params = collections.OrderedDict(tuple(sig.parameters.items())) - for name in ('a_po', 'b_po', 'c_po'): - new_params[name] = new_params[name].replace(kind=P.POSITIONAL_ONLY) - new_sig = sig.replace(parameters=new_params.values()) - test.__signature__ = new_sig - self.assertEqual(self.call(test, 1, 2, 4, 5, bar=6), (1, 2, 4, 5, 6, {})) From webhook-mailer at python.org Fri Apr 14 03:40:35 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Fri, 14 Apr 2023 07:40:35 -0000 Subject: [Python-checkins] Fix syntax typo in isolating extensions doc (#103516) Message-ID: https://github.com/python/cpython/commit/282f0d26e376b6c8d8cc039b23b649422acc30e9 commit: 282f0d26e376b6c8d8cc039b23b649422acc30e9 branch: main author: AN Long committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-04-14T00:40:25-07:00 summary: Fix syntax typo in isolating extensions doc (#103516) files: M Doc/howto/isolating-extensions.rst diff --git a/Doc/howto/isolating-extensions.rst b/Doc/howto/isolating-extensions.rst index 2eddb582da7c..0262054ae2b4 100644 --- a/Doc/howto/isolating-extensions.rst +++ b/Doc/howto/isolating-extensions.rst @@ -372,7 +372,7 @@ To save a some tedious error-handling boilerplate code, you can combine these two steps with :c:func:`PyType_GetModuleState`, resulting in:: my_struct *state = (my_struct*)PyType_GetModuleState(type); - if (state === NULL) { + if (state == NULL) { return NULL; } @@ -435,7 +435,7 @@ For example:: PyObject *kwnames) { my_struct *state = (my_struct*)PyType_GetModuleState(defining_class); - if (state === NULL) { + if (state == NULL) { return NULL; } ... // rest of logic @@ -479,7 +479,7 @@ to get the state:: PyObject *module = PyType_GetModuleByDef(Py_TYPE(self), &module_def); my_struct *state = (my_struct*)PyModule_GetState(module); - if (state === NULL) { + if (state == NULL) { return NULL; } From webhook-mailer at python.org Fri Apr 14 03:44:17 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Fri, 14 Apr 2023 07:44:17 -0000 Subject: [Python-checkins] ipaddress: Remove non-existent ip_str param from docstring (#103461) Message-ID: https://github.com/python/cpython/commit/9cc1960df65e4bdcfd127f1fab1834e91fd13e52 commit: 9cc1960df65e4bdcfd127f1fab1834e91fd13e52 branch: main author: Sergii Dymchenko committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-04-14T00:44:10-07:00 summary: ipaddress: Remove non-existent ip_str param from docstring (#103461) files: M Lib/ipaddress.py diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 1cb71d8032e1..af1d5c4800cc 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1821,9 +1821,6 @@ def _string_from_ip_int(cls, ip_int=None): def _explode_shorthand_ip_string(self): """Expand a shortened IPv6 address. - Args: - ip_str: A string, the IPv6 address. - Returns: A string, the expanded IPv6 address. From webhook-mailer at python.org Fri Apr 14 03:45:21 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Fri, 14 Apr 2023 07:45:21 -0000 Subject: [Python-checkins] Remove double space in import error message (#103458) Message-ID: https://github.com/python/cpython/commit/1aa376f946ef68ba46937019a424d925bf5b9611 commit: 1aa376f946ef68ba46937019a424d925bf5b9611 branch: main author: Ned Batchelder committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-04-14T00:45:14-07:00 summary: Remove double space in import error message (#103458) files: M Lib/importlib/_bootstrap.py diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index 22fa2469964a..e4fcaa61e6de 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -1260,7 +1260,7 @@ def _find_and_load_unlocked(name, import_): try: path = parent_module.__path__ except AttributeError: - msg = f'{_ERR_MSG_PREFIX} {name!r}; {parent!r} is not a package' + msg = f'{_ERR_MSG_PREFIX}{name!r}; {parent!r} is not a package' raise ModuleNotFoundError(msg, name=name) from None parent_spec = parent_module.__spec__ child = name.rpartition('.')[2] From webhook-mailer at python.org Fri Apr 14 05:01:18 2023 From: webhook-mailer at python.org (hugovk) Date: Fri, 14 Apr 2023 09:01:18 -0000 Subject: [Python-checkins] gh-103180: Add CI timeouts to all GitHub Actions jobs (#103437) Message-ID: https://github.com/python/cpython/commit/be8903eb9d66ef1229f93a3a6036aeafc3bb0bda commit: be8903eb9d66ef1229f93a3a6036aeafc3bb0bda branch: main author: Nikita Sobolev committer: hugovk date: 2023-04-14T12:01:10+03:00 summary: gh-103180: Add CI timeouts to all GitHub Actions jobs (#103437) files: M .github/workflows/build.yml M .github/workflows/build_msi.yml M .github/workflows/doc.yml M .github/workflows/new-bugs-announce-notifier.yml M .github/workflows/project-updater.yml M .github/workflows/require-pr-label.yml M .github/workflows/stale.yml M .github/workflows/verify-ensurepip-wheels.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4e5328282f12..7eba212cbb9a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,6 +33,7 @@ jobs: check_source: name: 'Check for source changes' runs-on: ubuntu-latest + timeout-minutes: 10 outputs: run_tests: ${{ steps.check.outputs.run_tests }} steps: @@ -63,6 +64,7 @@ jobs: check_generated_files: name: 'Check if generated files are up to date' runs-on: ubuntu-latest + timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' steps: @@ -118,6 +120,7 @@ jobs: build_win32: name: 'Windows (x86)' runs-on: windows-latest + timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: @@ -126,7 +129,6 @@ jobs: - uses: actions/checkout at v3 - name: Build CPython run: .\PCbuild\build.bat -e -d -p Win32 - timeout-minutes: 30 - name: Display build info run: .\python.bat -m test.pythoninfo - name: Tests @@ -135,6 +137,7 @@ jobs: build_win_amd64: name: 'Windows (x64)' runs-on: windows-latest + timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: @@ -145,7 +148,6 @@ jobs: run: echo "::add-matcher::.github/problem-matchers/msvc.json" - name: Build CPython run: .\PCbuild\build.bat -e -d -p x64 - timeout-minutes: 30 - name: Display build info run: .\python.bat -m test.pythoninfo - name: Tests @@ -154,6 +156,7 @@ jobs: build_macos: name: 'macOS' runs-on: macos-latest + timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: @@ -184,6 +187,7 @@ jobs: build_ubuntu: name: 'Ubuntu' runs-on: ubuntu-20.04 + timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: @@ -241,6 +245,7 @@ jobs: build_ubuntu_ssltests: name: 'Ubuntu SSL tests with OpenSSL' runs-on: ubuntu-20.04 + timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' strategy: @@ -290,6 +295,7 @@ jobs: build_asan: name: 'Address sanitizer' runs-on: ubuntu-20.04 + timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: diff --git a/.github/workflows/build_msi.yml b/.github/workflows/build_msi.yml index 5f1dcae190ef..2bed09014e0f 100644 --- a/.github/workflows/build_msi.yml +++ b/.github/workflows/build_msi.yml @@ -26,6 +26,7 @@ jobs: build: name: Windows Installer runs-on: windows-latest + timeout-minutes: 60 strategy: matrix: type: [x86, x64, arm64] diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 314a7da647ff..3101b30231c3 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -36,6 +36,7 @@ jobs: build_doc: name: 'Docs' runs-on: ubuntu-latest + timeout-minutes: 60 steps: - uses: actions/checkout at v3 - name: Register Sphinx problem matcher @@ -80,6 +81,7 @@ jobs: doctest: name: 'Doctest' runs-on: ubuntu-latest + timeout-minutes: 60 steps: - uses: actions/checkout at v3 - name: Register Sphinx problem matcher diff --git a/.github/workflows/new-bugs-announce-notifier.yml b/.github/workflows/new-bugs-announce-notifier.yml index b2a76ef7d361..73806c5d6d58 100644 --- a/.github/workflows/new-bugs-announce-notifier.yml +++ b/.github/workflows/new-bugs-announce-notifier.yml @@ -11,6 +11,7 @@ permissions: jobs: notify-new-bugs-announce: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/setup-node at v3 with: diff --git a/.github/workflows/project-updater.yml b/.github/workflows/project-updater.yml index 99c7a05ae8ca..dde923b26c2a 100644 --- a/.github/workflows/project-updater.yml +++ b/.github/workflows/project-updater.yml @@ -13,6 +13,7 @@ jobs: add-to-project: name: Add issues to projects runs-on: ubuntu-latest + timeout-minutes: 10 strategy: matrix: include: @@ -22,7 +23,7 @@ jobs: - { project: 3, label: expert-subinterpreters } - { project: 29, label: expert-asyncio } - { project: 32, label: sprint } - + steps: - uses: actions/add-to-project at v0.1.0 with: diff --git a/.github/workflows/require-pr-label.yml b/.github/workflows/require-pr-label.yml index e847bae155e2..151a60c2c04d 100644 --- a/.github/workflows/require-pr-label.yml +++ b/.github/workflows/require-pr-label.yml @@ -8,6 +8,7 @@ jobs: label: name: DO-NOT-MERGE runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: mheap/github-action-required-labels at v4 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index d79e856c87e7..94676f5ee5ff 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -12,6 +12,7 @@ jobs: if: github.repository_owner == 'python' runs-on: ubuntu-latest + timeout-minutes: 10 steps: - name: "Check PRs" diff --git a/.github/workflows/verify-ensurepip-wheels.yml b/.github/workflows/verify-ensurepip-wheels.yml index 969515ed287b..d4a2cb6846c1 100644 --- a/.github/workflows/verify-ensurepip-wheels.yml +++ b/.github/workflows/verify-ensurepip-wheels.yml @@ -23,6 +23,7 @@ concurrency: jobs: verify: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout at v3 - uses: actions/setup-python at v4 From webhook-mailer at python.org Fri Apr 14 10:04:23 2023 From: webhook-mailer at python.org (zware) Date: Fri, 14 Apr 2023 14:04:23 -0000 Subject: [Python-checkins] gh-103532: Remove TKINTER_PROTECT_LOADTK code (GH-103535) Message-ID: https://github.com/python/cpython/commit/69e2c42f42f1d6fb1287ac5f9c6d19f2822df8fe commit: 69e2c42f42f1d6fb1287ac5f9c6d19f2822df8fe branch: main author: Christopher Chavez committer: zware date: 2023-04-14T09:04:16-05:00 summary: gh-103532: Remove TKINTER_PROTECT_LOADTK code (GH-103535) This was only needed for Tk 8.4.13 and older, but Tkinter already requires at least 8.5.12. files: M Modules/_tkinter.c M Modules/tkappinit.c M Modules/tkinter.h diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 20e01c796685..385a05932a77 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -324,10 +324,6 @@ static int quitMainLoop = 0; static int errorInCmd = 0; static PyObject *excInCmd; -#ifdef TKINTER_PROTECT_LOADTK -static int tk_load_failed = 0; -#endif - static PyObject *Tkapp_UnicodeResult(TkappObject *); @@ -532,17 +528,7 @@ Tcl_AppInit(Tcl_Interp *interp) return TCL_OK; } -#ifdef TKINTER_PROTECT_LOADTK - if (tk_load_failed) { - PySys_WriteStderr("Tk_Init error: %s\n", TKINTER_LOADTK_ERRMSG); - return TCL_ERROR; - } -#endif - if (Tk_Init(interp) == TCL_ERROR) { -#ifdef TKINTER_PROTECT_LOADTK - tk_load_failed = 1; -#endif PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp)); return TCL_ERROR; } @@ -635,12 +621,6 @@ Tkapp_New(const char *screenName, const char *className, Tcl_SetVar(v->interp, "_tkinter_skip_tk_init", "1", TCL_GLOBAL_ONLY); } -#ifdef TKINTER_PROTECT_LOADTK - else if (tk_load_failed) { - Tcl_SetVar(v->interp, - "_tkinter_tk_failed", "1", TCL_GLOBAL_ONLY); - } -#endif /* some initial arguments need to be in argv */ if (sync || use) { @@ -702,18 +682,6 @@ Tkapp_New(const char *screenName, const char *className, if (Tcl_AppInit(v->interp) != TCL_OK) { PyObject *result = Tkinter_Error(v); -#ifdef TKINTER_PROTECT_LOADTK - if (wantTk) { - const char *_tkinter_tk_failed; - _tkinter_tk_failed = Tcl_GetVar(v->interp, - "_tkinter_tk_failed", TCL_GLOBAL_ONLY); - - if ( _tkinter_tk_failed != NULL && - strcmp(_tkinter_tk_failed, "1") == 0) { - tk_load_failed = 1; - } - } -#endif Py_DECREF((PyObject *)v); return (TkappObject *)result; } @@ -2780,18 +2748,6 @@ _tkinter_tkapp_loadtk_impl(TkappObject *self) const char * _tk_exists = NULL; int err; -#ifdef TKINTER_PROTECT_LOADTK - /* Up to Tk 8.4.13, Tk_Init deadlocks on the second call when the - * first call failed. - * To avoid the deadlock, we just refuse the second call through - * a static variable. - */ - if (tk_load_failed) { - PyErr_SetString(Tkinter_TclError, TKINTER_LOADTK_ERRMSG); - return NULL; - } -#endif - /* We want to guard against calling Tk_Init() multiple times */ CHECK_TCL_APPARTMENT; ENTER_TCL @@ -2811,9 +2767,6 @@ _tkinter_tkapp_loadtk_impl(TkappObject *self) if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0) { if (Tk_Init(interp) == TCL_ERROR) { Tkinter_Error(self); -#ifdef TKINTER_PROTECT_LOADTK - tk_load_failed = 1; -#endif return NULL; } } diff --git a/Modules/tkappinit.c b/Modules/tkappinit.c index 7616d9d319d2..67d6250318c6 100644 --- a/Modules/tkappinit.c +++ b/Modules/tkappinit.c @@ -18,18 +18,10 @@ #include "tkinter.h" -#ifdef TKINTER_PROTECT_LOADTK -/* See Tkapp_TkInit in _tkinter.c for the usage of tk_load_faile */ -static int tk_load_failed; -#endif - int Tcl_AppInit(Tcl_Interp *interp) { const char *_tkinter_skip_tk_init; -#ifdef TKINTER_PROTECT_LOADTK - const char *_tkinter_tk_failed; -#endif #ifdef TK_AQUA #ifndef MAX_PATH_LEN @@ -90,23 +82,7 @@ Tcl_AppInit(Tcl_Interp *interp) return TCL_OK; } -#ifdef TKINTER_PROTECT_LOADTK - _tkinter_tk_failed = Tcl_GetVar(interp, - "_tkinter_tk_failed", TCL_GLOBAL_ONLY); - - if (tk_load_failed || ( - _tkinter_tk_failed != NULL && - strcmp(_tkinter_tk_failed, "1") == 0)) { - Tcl_SetResult(interp, TKINTER_LOADTK_ERRMSG, TCL_STATIC); - return TCL_ERROR; - } -#endif - if (Tk_Init(interp) == TCL_ERROR) { -#ifdef TKINTER_PROTECT_LOADTK - tk_load_failed = 1; - Tcl_SetVar(interp, "_tkinter_tk_failed", "1", TCL_GLOBAL_ONLY); -#endif return TCL_ERROR; } diff --git a/Modules/tkinter.h b/Modules/tkinter.h index cb5a806b0c43..40281c217603 100644 --- a/Modules/tkinter.h +++ b/Modules/tkinter.h @@ -16,12 +16,4 @@ (TK_RELEASE_LEVEL << 8) | \ (TK_RELEASE_SERIAL << 0)) -/* Protect Tk 8.4.13 and older from a deadlock that happens when trying - * to load tk after a failed attempt. */ -#if TK_HEX_VERSION < 0x0804020e -#define TKINTER_PROTECT_LOADTK -#define TKINTER_LOADTK_ERRMSG \ - "Calling Tk_Init again after a previous call failed might deadlock" -#endif - #endif /* !TKINTER_H */ From webhook-mailer at python.org Fri Apr 14 11:29:13 2023 From: webhook-mailer at python.org (zware) Date: Fri, 14 Apr 2023 15:29:13 -0000 Subject: [Python-checkins] gh-103532: Add NEWS entry (#103542) Message-ID: https://github.com/python/cpython/commit/e32c197ad31436e8160d9c8c0bba65d89f8ee14d commit: e32c197ad31436e8160d9c8c0bba65d89f8ee14d branch: main author: Zachary Ware committer: zware date: 2023-04-14T10:28:53-05:00 summary: gh-103532: Add NEWS entry (#103542) files: A Misc/NEWS.d/next/Build/2023-04-14-10-24-37.gh-issue-103532.H1djkd.rst diff --git a/Misc/NEWS.d/next/Build/2023-04-14-10-24-37.gh-issue-103532.H1djkd.rst b/Misc/NEWS.d/next/Build/2023-04-14-10-24-37.gh-issue-103532.H1djkd.rst new file mode 100644 index 000000000000..ad981eafc591 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-04-14-10-24-37.gh-issue-103532.H1djkd.rst @@ -0,0 +1,4 @@ +The ``TKINTER_PROTECT_LOADTK`` macro is no longer defined or used in the +``_tkinter`` module. It was previously only defined when building against +Tk 8.4.13 and older, but Tk older than 8.5.12 has been unsupported since +:gh-issue:`91152`. From webhook-mailer at python.org Fri Apr 14 12:03:36 2023 From: webhook-mailer at python.org (zware) Date: Fri, 14 Apr 2023 16:03:36 -0000 Subject: [Python-checkins] gh-103532: Fix reST syntax in NEWS entry (GH-103544) Message-ID: https://github.com/python/cpython/commit/95ee7c47ab53eb0e26f2b2b4f681015f49c0bff7 commit: 95ee7c47ab53eb0e26f2b2b4f681015f49c0bff7 branch: main author: Zachary Ware committer: zware date: 2023-04-14T11:03:28-05:00 summary: gh-103532: Fix reST syntax in NEWS entry (GH-103544) files: M Misc/NEWS.d/next/Build/2023-04-14-10-24-37.gh-issue-103532.H1djkd.rst diff --git a/Misc/NEWS.d/next/Build/2023-04-14-10-24-37.gh-issue-103532.H1djkd.rst b/Misc/NEWS.d/next/Build/2023-04-14-10-24-37.gh-issue-103532.H1djkd.rst index ad981eafc591..255c9833282c 100644 --- a/Misc/NEWS.d/next/Build/2023-04-14-10-24-37.gh-issue-103532.H1djkd.rst +++ b/Misc/NEWS.d/next/Build/2023-04-14-10-24-37.gh-issue-103532.H1djkd.rst @@ -1,4 +1,4 @@ The ``TKINTER_PROTECT_LOADTK`` macro is no longer defined or used in the ``_tkinter`` module. It was previously only defined when building against Tk 8.4.13 and older, but Tk older than 8.5.12 has been unsupported since -:gh-issue:`91152`. +gh-issue-91152. From webhook-mailer at python.org Fri Apr 14 14:47:21 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Fri, 14 Apr 2023 18:47:21 -0000 Subject: [Python-checkins] gh-103527: Add make deps for _codecs_* and _multibytecodec (#103528) Message-ID: https://github.com/python/cpython/commit/3d71b5ec5ecccc14c00707d73ebbc907877b3448 commit: 3d71b5ec5ecccc14c00707d73ebbc907877b3448 branch: main author: Erlend E. Aasland committer: erlend-aasland date: 2023-04-14T20:47:13+02:00 summary: gh-103527: Add make deps for _codecs_* and _multibytecodec (#103528) files: M Makefile.pre.in diff --git a/Makefile.pre.in b/Makefile.pre.in index afd503ef1263..a4633caba305 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2662,6 +2662,13 @@ MODULE__SOCKET_DEPS=$(srcdir)/Modules/socketmodule.h $(srcdir)/Modules/addrinfo. MODULE__SSL_DEPS=$(srcdir)/Modules/_ssl.h $(srcdir)/Modules/_ssl/cert.c $(srcdir)/Modules/_ssl/debughelpers.c $(srcdir)/Modules/_ssl/misc.c $(srcdir)/Modules/_ssl_data.h $(srcdir)/Modules/_ssl_data_111.h $(srcdir)/Modules/_ssl_data_300.h $(srcdir)/Modules/socketmodule.h MODULE__TESTCAPI_DEPS=$(srcdir)/Modules/_testcapi/testcapi_long.h $(srcdir)/Modules/_testcapi/parts.h MODULE__SQLITE3_DEPS=$(srcdir)/Modules/_sqlite/connection.h $(srcdir)/Modules/_sqlite/cursor.h $(srcdir)/Modules/_sqlite/microprotocols.h $(srcdir)/Modules/_sqlite/module.h $(srcdir)/Modules/_sqlite/prepare_protocol.h $(srcdir)/Modules/_sqlite/row.h $(srcdir)/Modules/_sqlite/util.h +MODULE__CODECS_CN_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_cn.h $(srcdir)/Modules/cjkcodecs/cjkcodecs.h +MODULE__CODECS_HK_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_hk.h $(srcdir)/Modules/cjkcodecs/cjkcodecs.h +MODULE__CODECS_ISO2022_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_jisx0213_pair.h $(srcdir)/Modules/cjkcodecs/cjkcodecs.h $(srcdir)/Modules/cjkcodecs/alg_jisx0201.h $(srcdir)/Modules/cjkcodecs/emu_jisx0213_2000.h +MODULE__CODECS_JP_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_jisx0213_pair.h $(srcdir)/Modules/cjkcodecs/cjkcodecs.h $(srcdir)/Modules/cjkcodecs/alg_jisx0201.h $(srcdir)/Modules/cjkcodecs/emu_jisx0213_2000.h $(srcdir)/Modules/cjkcodecs/mappings_jp.h +MODULE__CODECS_KR_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_kr.h $(srcdir)/Modules/cjkcodecs/cjkcodecs.h +MODULE__CODECS_TW_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_tw.h $(srcdir)/Modules/cjkcodecs/cjkcodecs.h +MODULE__MULTIBYTECODEC_DEPS=$(srcdir)/Modules/cjkcodecs/multibytecodec.h # IF YOU PUT ANYTHING HERE IT WILL GO AWAY # Local Variables: From webhook-mailer at python.org Fri Apr 14 16:40:38 2023 From: webhook-mailer at python.org (iritkatriel) Date: Fri, 14 Apr 2023 20:40:38 -0000 Subject: [Python-checkins] gh-101517: Add regression test for a lineno bug in try/except* impacting pdb (#103547) Message-ID: https://github.com/python/cpython/commit/7c1b0a46c61f8bf8e2039bba1bff11b6ae20e56b commit: 7c1b0a46c61f8bf8e2039bba1bff11b6ae20e56b branch: main author: Tian Gao committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-04-14T21:40:31+01:00 summary: gh-101517: Add regression test for a lineno bug in try/except* impacting pdb (#103547) files: M Lib/test/test_pdb.py diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 9ad9a1c52ac1..94b441720f25 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1700,6 +1700,26 @@ def test_pdb_issue_gh_103225(): (Pdb) continue """ +def test_pdb_issue_gh_101517(): + """See GH-101517 + + Make sure pdb doesn't crash when the exception is caught in a try/except* block + + >>> def test_function(): + ... try: + ... raise KeyError + ... except* Exception as e: + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE + ... 'continue' + ... ]): + ... test_function() + --Return-- + > (None)test_function()->None + (Pdb) continue + """ + @support.requires_subprocess() class PdbTestCase(unittest.TestCase): From webhook-mailer at python.org Fri Apr 14 16:55:50 2023 From: webhook-mailer at python.org (barneygale) Date: Fri, 14 Apr 2023 20:55:50 -0000 Subject: [Python-checkins] GH-78079: Fix UNC device path root normalization in pathlib (GH-102003) Message-ID: https://github.com/python/cpython/commit/8af8f52d175959f03cf4a2786b6a81ec09e15e95 commit: 8af8f52d175959f03cf4a2786b6a81ec09e15e95 branch: main author: Barney Gale committer: barneygale date: 2023-04-14T21:55:41+01:00 summary: GH-78079: Fix UNC device path root normalization in pathlib (GH-102003) We no longer add a root to device paths such as `//./PhysicalDrive0`, `//?/BootPartition` and `//./c:` while normalizing. We also avoid adding a root to incomplete UNC share paths, like `//`, `//a` and `//a/`. Co-authored-by: Eryk Sun files: A Misc/NEWS.d/next/Library/2023-02-17-21-14-40.gh-issue-78079.z3Szr6.rst M Lib/pathlib.py M Lib/test/test_ntpath.py M Lib/test/test_pathlib.py diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 4ae1fae6f4b3..f43f01ef41a9 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -322,9 +322,14 @@ def _parse_path(cls, path): if altsep: path = path.replace(altsep, sep) drv, root, rel = cls._flavour.splitroot(path) - if drv.startswith(sep): - # pathlib assumes that UNC paths always have a root. - root = sep + if not root and drv.startswith(sep) and not drv.endswith(sep): + drv_parts = drv.split(sep) + if len(drv_parts) == 4 and drv_parts[2] not in '?.': + # e.g. //server/share + root = sep + elif len(drv_parts) == 6: + # e.g. //?/unc/server/share + root = sep parsed = [sys.intern(str(x)) for x in rel.split(sep) if x and x != '.'] return drv, root, parsed diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index 42b9587ca181..0e57c165ca98 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -169,6 +169,7 @@ def test_splitroot(self): # gh-81790: support device namespace, including UNC drives. tester('ntpath.splitroot("//?/c:")', ("//?/c:", "", "")) + tester('ntpath.splitroot("//./c:")', ("//./c:", "", "")) tester('ntpath.splitroot("//?/c:/")', ("//?/c:", "/", "")) tester('ntpath.splitroot("//?/c:/dir")', ("//?/c:", "/", "dir")) tester('ntpath.splitroot("//?/UNC")', ("//?/UNC", "", "")) @@ -179,8 +180,12 @@ def test_splitroot(self): tester('ntpath.splitroot("//?/VOLUME{00000000-0000-0000-0000-000000000000}/spam")', ('//?/VOLUME{00000000-0000-0000-0000-000000000000}', '/', 'spam')) tester('ntpath.splitroot("//?/BootPartition/")', ("//?/BootPartition", "/", "")) + tester('ntpath.splitroot("//./BootPartition/")', ("//./BootPartition", "/", "")) + tester('ntpath.splitroot("//./PhysicalDrive0")', ("//./PhysicalDrive0", "", "")) + tester('ntpath.splitroot("//./nul")', ("//./nul", "", "")) tester('ntpath.splitroot("\\\\?\\c:")', ("\\\\?\\c:", "", "")) + tester('ntpath.splitroot("\\\\.\\c:")', ("\\\\.\\c:", "", "")) tester('ntpath.splitroot("\\\\?\\c:\\")', ("\\\\?\\c:", "\\", "")) tester('ntpath.splitroot("\\\\?\\c:\\dir")', ("\\\\?\\c:", "\\", "dir")) tester('ntpath.splitroot("\\\\?\\UNC")', ("\\\\?\\UNC", "", "")) @@ -193,6 +198,9 @@ def test_splitroot(self): tester('ntpath.splitroot("\\\\?\\VOLUME{00000000-0000-0000-0000-000000000000}\\spam")', ('\\\\?\\VOLUME{00000000-0000-0000-0000-000000000000}', '\\', 'spam')) tester('ntpath.splitroot("\\\\?\\BootPartition\\")', ("\\\\?\\BootPartition", "\\", "")) + tester('ntpath.splitroot("\\\\.\\BootPartition\\")', ("\\\\.\\BootPartition", "\\", "")) + tester('ntpath.splitroot("\\\\.\\PhysicalDrive0")', ("\\\\.\\PhysicalDrive0", "", "")) + tester('ntpath.splitroot("\\\\.\\nul")', ("\\\\.\\nul", "", "")) # gh-96290: support partial/invalid UNC drives tester('ntpath.splitroot("//")', ("//", "", "")) # empty server & missing share diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 3c6da94d0946..120b70f21973 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -810,6 +810,9 @@ def test_drive_root_parts(self): check(('c:/a',), 'c:', '\\', ('c:\\', 'a')) check(('/a',), '', '\\', ('\\', 'a')) # UNC paths. + check(('//',), '\\\\', '', ('\\\\',)) + check(('//a',), '\\\\a', '', ('\\\\a',)) + check(('//a/',), '\\\\a\\', '', ('\\\\a\\',)) check(('//a/b',), '\\\\a\\b', '\\', ('\\\\a\\b\\',)) check(('//a/b/',), '\\\\a\\b', '\\', ('\\\\a\\b\\',)) check(('//a/b/c',), '\\\\a\\b', '\\', ('\\\\a\\b\\', 'c')) @@ -823,12 +826,26 @@ def test_drive_root_parts(self): # UNC paths. check(('a', '//b/c//', 'd'), '\\\\b\\c', '\\', ('\\\\b\\c\\', 'd')) # Extended paths. + check(('//./c:',), '\\\\.\\c:', '', ('\\\\.\\c:',)) check(('//?/c:/',), '\\\\?\\c:', '\\', ('\\\\?\\c:\\',)) check(('//?/c:/a',), '\\\\?\\c:', '\\', ('\\\\?\\c:\\', 'a')) check(('//?/c:/a', '/b'), '\\\\?\\c:', '\\', ('\\\\?\\c:\\', 'b')) # Extended UNC paths (format is "\\?\UNC\server\share"). + check(('//?',), '\\\\?', '', ('\\\\?',)) + check(('//?/',), '\\\\?\\', '', ('\\\\?\\',)) + check(('//?/UNC',), '\\\\?\\UNC', '', ('\\\\?\\UNC',)) + check(('//?/UNC/',), '\\\\?\\UNC\\', '', ('\\\\?\\UNC\\',)) + check(('//?/UNC/b',), '\\\\?\\UNC\\b', '', ('\\\\?\\UNC\\b',)) + check(('//?/UNC/b/',), '\\\\?\\UNC\\b\\', '', ('\\\\?\\UNC\\b\\',)) check(('//?/UNC/b/c',), '\\\\?\\UNC\\b\\c', '\\', ('\\\\?\\UNC\\b\\c\\',)) + check(('//?/UNC/b/c/',), '\\\\?\\UNC\\b\\c', '\\', ('\\\\?\\UNC\\b\\c\\',)) check(('//?/UNC/b/c/d',), '\\\\?\\UNC\\b\\c', '\\', ('\\\\?\\UNC\\b\\c\\', 'd')) + # UNC device paths + check(('//./BootPartition/',), '\\\\.\\BootPartition', '\\', ('\\\\.\\BootPartition\\',)) + check(('//?/BootPartition/',), '\\\\?\\BootPartition', '\\', ('\\\\?\\BootPartition\\',)) + check(('//./PhysicalDrive0',), '\\\\.\\PhysicalDrive0', '', ('\\\\.\\PhysicalDrive0',)) + check(('//?/Volume{}/',), '\\\\?\\Volume{}', '\\', ('\\\\?\\Volume{}\\',)) + check(('//./nul',), '\\\\.\\nul', '', ('\\\\.\\nul',)) # Second part has a root but not drive. check(('a', '/b', 'c'), '', '\\', ('\\', 'b', 'c')) check(('Z:/a', '/b', 'c'), 'Z:', '\\', ('Z:\\', 'b', 'c')) @@ -1371,6 +1388,13 @@ def test_join(self): self.assertEqual(pp, P('C:/a/b/dd:s')) pp = p.joinpath(P('E:d:s')) self.assertEqual(pp, P('E:d:s')) + # Joining onto a UNC path with no root + pp = P('//').joinpath('server') + self.assertEqual(pp, P('//server')) + pp = P('//server').joinpath('share') + self.assertEqual(pp, P('//server/share')) + pp = P('//./BootPartition').joinpath('Windows') + self.assertEqual(pp, P('//./BootPartition/Windows')) def test_div(self): # Basically the same as joinpath(). diff --git a/Misc/NEWS.d/next/Library/2023-02-17-21-14-40.gh-issue-78079.z3Szr6.rst b/Misc/NEWS.d/next/Library/2023-02-17-21-14-40.gh-issue-78079.z3Szr6.rst new file mode 100644 index 000000000000..bbb9ac3e3f8f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-17-21-14-40.gh-issue-78079.z3Szr6.rst @@ -0,0 +1,3 @@ +Fix incorrect normalization of UNC device path roots, and partial UNC share +path roots, in :class:`pathlib.PurePath`. Pathlib no longer appends a +trailing slash to such paths. From webhook-mailer at python.org Sat Apr 15 01:54:10 2023 From: webhook-mailer at python.org (iritkatriel) Date: Sat, 15 Apr 2023 05:54:10 -0000 Subject: [Python-checkins] gh-102114: Make dis print more concise tracebacks for syntax errors in str inputs (#102115) Message-ID: https://github.com/python/cpython/commit/2b6f5c3483597abcb8422508aeffab04f500f568 commit: 2b6f5c3483597abcb8422508aeffab04f500f568 branch: main author: chgnrdv <52372310+chgnrdv at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-04-15T06:53:31+01:00 summary: gh-102114: Make dis print more concise tracebacks for syntax errors in str inputs (#102115) files: A Misc/NEWS.d/next/Library/2023-02-21-14-57-34.gh-issue-102114.uUDQzb.rst M Lib/dis.py M Lib/test/test_dis.py diff --git a/Lib/dis.py b/Lib/dis.py index b39b28353301..6a7fcb8a1a00 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -64,10 +64,10 @@ def _try_compile(source, name): expect code objects """ try: - c = compile(source, name, 'eval') + return compile(source, name, 'eval') except SyntaxError: - c = compile(source, name, 'exec') - return c + pass + return compile(source, name, 'exec') def dis(x=None, *, file=None, depth=None, show_caches=False, adaptive=False): """Disassemble classes, methods, functions, and other compiled objects. diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 0a60a979614d..2d5c73c9adc9 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1067,6 +1067,13 @@ def check(expected, **kwargs): check(dis_nested_2, depth=None) check(dis_nested_2) + def test__try_compile_no_context_exc_on_error(self): + # see gh-102114 + try: + dis._try_compile(")", "") + except Exception as e: + self.assertIsNone(e.__context__) + @staticmethod def code_quicken(f, times=ADAPTIVE_WARMUP_DELAY): for _ in range(times): diff --git a/Misc/NEWS.d/next/Library/2023-02-21-14-57-34.gh-issue-102114.uUDQzb.rst b/Misc/NEWS.d/next/Library/2023-02-21-14-57-34.gh-issue-102114.uUDQzb.rst new file mode 100644 index 000000000000..4140c9a96cd2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-21-14-57-34.gh-issue-102114.uUDQzb.rst @@ -0,0 +1 @@ +Functions in the :mod:`dis` module that accept a source code string as argument now print a more concise traceback when the string contains a syntax or indentation error. From webhook-mailer at python.org Sat Apr 15 06:44:36 2023 From: webhook-mailer at python.org (hugovk) Date: Sat, 15 Apr 2023 10:44:36 -0000 Subject: [Python-checkins] [3.11] gh-103180: Add CI timeouts to all GitHub Actions jobs (GH-103437). (#103543) Message-ID: https://github.com/python/cpython/commit/a3242c72a8f50cb7025c502f09c8a051a029b561 commit: a3242c72a8f50cb7025c502f09c8a051a029b561 branch: 3.11 author: Nikita Sobolev committer: hugovk date: 2023-04-15T13:44:29+03:00 summary: [3.11] gh-103180: Add CI timeouts to all GitHub Actions jobs (GH-103437). (#103543) files: M .github/workflows/build.yml M .github/workflows/build_msi.yml M .github/workflows/doc.yml M .github/workflows/new-bugs-announce-notifier.yml M .github/workflows/require-pr-label.yml M .github/workflows/stale.yml M .github/workflows/verify-ensurepip-wheels.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2df4cfb9e2ae..597797f73585 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,6 +33,7 @@ jobs: check_source: name: 'Check for source changes' runs-on: ubuntu-latest + timeout-minutes: 10 outputs: run_tests: ${{ steps.check.outputs.run_tests }} run_ssl_tests: ${{ steps.check.outputs.run_ssl_tests }} @@ -96,6 +97,7 @@ jobs: check_generated_files: name: 'Check if generated files are up to date' runs-on: ubuntu-latest + timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' steps: @@ -148,6 +150,7 @@ jobs: build_win32: name: 'Windows (x86)' runs-on: windows-latest + timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: @@ -156,7 +159,6 @@ jobs: - uses: actions/checkout at v3 - name: Build CPython run: .\PCbuild\build.bat -e -d -p Win32 - timeout-minutes: 30 - name: Display build info run: .\python.bat -m test.pythoninfo - name: Tests @@ -165,6 +167,7 @@ jobs: build_win_amd64: name: 'Windows (x64)' runs-on: windows-latest + timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: @@ -175,7 +178,6 @@ jobs: run: echo "::add-matcher::.github/problem-matchers/msvc.json" - name: Build CPython run: .\PCbuild\build.bat -e -d -p x64 - timeout-minutes: 30 - name: Display build info run: .\python.bat -m test.pythoninfo - name: Tests @@ -184,6 +186,7 @@ jobs: build_macos: name: 'macOS' runs-on: macos-latest + timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: @@ -214,6 +217,7 @@ jobs: build_ubuntu: name: 'Ubuntu' runs-on: ubuntu-20.04 + timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: @@ -271,6 +275,7 @@ jobs: build_ubuntu_ssltests: name: 'Ubuntu SSL tests with OpenSSL' runs-on: ubuntu-20.04 + timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' && needs.check_source.outputs.run_ssl_tests == 'true' strategy: @@ -320,6 +325,7 @@ jobs: build_asan: name: 'Address sanitizer' runs-on: ubuntu-20.04 + timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: diff --git a/.github/workflows/build_msi.yml b/.github/workflows/build_msi.yml index 5243dbba5f6b..1b9c1d141d13 100644 --- a/.github/workflows/build_msi.yml +++ b/.github/workflows/build_msi.yml @@ -34,6 +34,7 @@ jobs: build_win32: name: 'Windows (x86) Installer' runs-on: windows-latest + timeout-minutes: 60 steps: - uses: actions/checkout at v3 - name: Build CPython installer @@ -42,6 +43,7 @@ jobs: build_win_amd64: name: 'Windows (x64) Installer' runs-on: windows-latest + timeout-minutes: 60 steps: - uses: actions/checkout at v3 - name: Build CPython installer @@ -50,6 +52,7 @@ jobs: build_win_arm64: name: 'Windows (ARM64) Installer' runs-on: windows-latest + timeout-minutes: 60 steps: - uses: actions/checkout at v3 - name: Build CPython installer diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index af5c5d0ad2e2..77319c9f9112 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -36,6 +36,7 @@ jobs: build_doc: name: 'Docs' runs-on: ubuntu-latest + timeout-minutes: 60 steps: - uses: actions/checkout at v3 - name: Register Sphinx problem matcher @@ -62,6 +63,7 @@ jobs: doctest: name: 'Doctest' runs-on: ubuntu-latest + timeout-minutes: 60 steps: - uses: actions/checkout at v3 - name: Register Sphinx problem matcher diff --git a/.github/workflows/new-bugs-announce-notifier.yml b/.github/workflows/new-bugs-announce-notifier.yml index b2b63472d834..d3b982455dd9 100644 --- a/.github/workflows/new-bugs-announce-notifier.yml +++ b/.github/workflows/new-bugs-announce-notifier.yml @@ -11,6 +11,7 @@ permissions: jobs: notify-new-bugs-announce: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/setup-node at v3 with: diff --git a/.github/workflows/require-pr-label.yml b/.github/workflows/require-pr-label.yml index e847bae155e2..151a60c2c04d 100644 --- a/.github/workflows/require-pr-label.yml +++ b/.github/workflows/require-pr-label.yml @@ -8,6 +8,7 @@ jobs: label: name: DO-NOT-MERGE runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: mheap/github-action-required-labels at v4 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index f422707afb9e..81fb838728bd 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -12,6 +12,7 @@ jobs: if: github.repository_owner == 'python' runs-on: ubuntu-latest + timeout-minutes: 10 steps: - name: "Check PRs" diff --git a/.github/workflows/verify-ensurepip-wheels.yml b/.github/workflows/verify-ensurepip-wheels.yml index 9f4754f912b0..030fbc6ce295 100644 --- a/.github/workflows/verify-ensurepip-wheels.yml +++ b/.github/workflows/verify-ensurepip-wheels.yml @@ -23,6 +23,7 @@ concurrency: jobs: verify: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout at v3 - uses: actions/setup-python at v4 From webhook-mailer at python.org Sat Apr 15 12:35:25 2023 From: webhook-mailer at python.org (barneygale) Date: Sat, 15 Apr 2023 16:35:25 -0000 Subject: [Python-checkins] GH-103517: Improve tests for `pathlib.Path.walk()` (GH-103518) Message-ID: https://github.com/python/cpython/commit/0097c36e07eeb516bcccba34feb4d494a67832d5 commit: 0097c36e07eeb516bcccba34feb4d494a67832d5 branch: main author: Barney Gale committer: barneygale date: 2023-04-15T17:35:17+01:00 summary: GH-103517: Improve tests for `pathlib.Path.walk()` (GH-103518) files: M Lib/test/test_pathlib.py diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 120b70f21973..76cfadeedcea 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -2702,20 +2702,20 @@ def setUp(self): del self.sub2_tree[1][:1] def test_walk_topdown(self): - all = list(self.walk_path.walk()) - - self.assertEqual(len(all), 4) - # We can't know which order SUB1 and SUB2 will appear in. - # Not flipped: TESTFN, SUB1, SUB11, SUB2 - # flipped: TESTFN, SUB2, SUB1, SUB11 - flipped = all[0][1][0] != "SUB1" - all[0][1].sort() - all[3 - 2 * flipped][-1].sort() - all[3 - 2 * flipped][1].sort() - self.assertEqual(all[0], (self.walk_path, ["SUB1", "SUB2"], ["tmp1"])) - self.assertEqual(all[1 + flipped], (self.sub1_path, ["SUB11"], ["tmp2"])) - self.assertEqual(all[2 + flipped], (self.sub11_path, [], [])) - self.assertEqual(all[3 - 2 * flipped], self.sub2_tree) + walker = self.walk_path.walk() + entry = next(walker) + entry[1].sort() # Ensure we visit SUB1 before SUB2 + self.assertEqual(entry, (self.walk_path, ["SUB1", "SUB2"], ["tmp1"])) + entry = next(walker) + self.assertEqual(entry, (self.sub1_path, ["SUB11"], ["tmp2"])) + entry = next(walker) + self.assertEqual(entry, (self.sub11_path, [], [])) + entry = next(walker) + entry[1].sort() + entry[2].sort() + self.assertEqual(entry, self.sub2_tree) + with self.assertRaises(StopIteration): + next(walker) def test_walk_prune(self, walk_path=None): if walk_path is None: @@ -2739,24 +2739,37 @@ def test_file_like_path(self): self.test_walk_prune(FakePath(self.walk_path).__fspath__()) def test_walk_bottom_up(self): - all = list(self.walk_path.walk( top_down=False)) - - self.assertEqual(len(all), 4, all) - # We can't know which order SUB1 and SUB2 will appear in. - # Not flipped: SUB11, SUB1, SUB2, TESTFN - # flipped: SUB2, SUB11, SUB1, TESTFN - flipped = all[3][1][0] != "SUB1" - all[3][1].sort() - all[2 - 2 * flipped][-1].sort() - all[2 - 2 * flipped][1].sort() - self.assertEqual(all[3], - (self.walk_path, ["SUB1", "SUB2"], ["tmp1"])) - self.assertEqual(all[flipped], - (self.sub11_path, [], [])) - self.assertEqual(all[flipped + 1], - (self.sub1_path, ["SUB11"], ["tmp2"])) - self.assertEqual(all[2 - 2 * flipped], - self.sub2_tree) + seen_testfn = seen_sub1 = seen_sub11 = seen_sub2 = False + for path, dirnames, filenames in self.walk_path.walk(top_down=False): + if path == self.walk_path: + self.assertFalse(seen_testfn) + self.assertTrue(seen_sub1) + self.assertTrue(seen_sub2) + self.assertEqual(sorted(dirnames), ["SUB1", "SUB2"]) + self.assertEqual(filenames, ["tmp1"]) + seen_testfn = True + elif path == self.sub1_path: + self.assertFalse(seen_testfn) + self.assertFalse(seen_sub1) + self.assertTrue(seen_sub11) + self.assertEqual(dirnames, ["SUB11"]) + self.assertEqual(filenames, ["tmp2"]) + seen_sub1 = True + elif path == self.sub11_path: + self.assertFalse(seen_sub1) + self.assertFalse(seen_sub11) + self.assertEqual(dirnames, []) + self.assertEqual(filenames, []) + seen_sub11 = True + elif path == self.sub2_path: + self.assertFalse(seen_testfn) + self.assertFalse(seen_sub2) + self.assertEqual(sorted(dirnames), sorted(self.sub2_tree[1])) + self.assertEqual(sorted(filenames), sorted(self.sub2_tree[2])) + seen_sub2 = True + else: + raise AssertionError(f"Unexpected path: {path}") + self.assertTrue(seen_testfn) @os_helper.skip_unless_symlink def test_walk_follow_symlinks(self): From webhook-mailer at python.org Sat Apr 15 16:48:47 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Sat, 15 Apr 2023 20:48:47 -0000 Subject: [Python-checkins] gh-103553: Improve `test_inspect`: add more assertions, remove unused (#103554) Message-ID: https://github.com/python/cpython/commit/4fe1c4b97e39429abbb9c2117fe40f585de00887 commit: 4fe1c4b97e39429abbb9c2117fe40f585de00887 branch: main author: Nikita Sobolev committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-04-15T13:48:31-07:00 summary: gh-103553: Improve `test_inspect`: add more assertions, remove unused (#103554) files: M Lib/test/test_inspect.py diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index cfdb992654c2..6b342b1f00d6 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1820,8 +1820,7 @@ def test_errors(self): self.assertEqualException(f, '2, 3, 4') self.assertEqualException(f, '1, 2, 3, a=1') self.assertEqualException(f, '2, 3, 4, c=5') - # XXX: success of this one depends on dict order - ## self.assertEqualException(f, '2, 3, 4, a=1, c=5') + self.assertEqualException(f, '2, 3, 4, a=1, c=5') # f got an unexpected keyword argument self.assertEqualException(f, 'c=2') self.assertEqualException(f, '2, c=3') @@ -1832,17 +1831,19 @@ def test_errors(self): self.assertEqualException(f, '1, a=2') self.assertEqualException(f, '1, **{"a":2}') self.assertEqualException(f, '1, 2, b=3') - # XXX: Python inconsistency - # - for functions and bound methods: unexpected keyword 'c' - # - for unbound methods: multiple values for keyword 'a' - #self.assertEqualException(f, '1, c=3, a=2') + self.assertEqualException(f, '1, c=3, a=2') # issue11256: f3 = self.makeCallable('**c') self.assertEqualException(f3, '1, 2') self.assertEqualException(f3, '1, 2, a=1, b=2') f4 = self.makeCallable('*, a, b=0') - self.assertEqualException(f3, '1, 2') - self.assertEqualException(f3, '1, 2, a=1, b=2') + self.assertEqualException(f4, '1, 2') + self.assertEqualException(f4, '1, 2, a=1, b=2') + self.assertEqualException(f4, 'a=1, a=3') + self.assertEqualException(f4, 'a=1, c=3') + self.assertEqualException(f4, 'a=1, a=3, b=4') + self.assertEqualException(f4, 'a=1, b=2, a=3, b=4') + self.assertEqualException(f4, 'a=1, a=2, a=3, b=4') # issue #20816: getcallargs() fails to iterate over non-existent # kwonlydefaults and raises a wrong TypeError @@ -2872,8 +2873,6 @@ def foo(cls, *, arg): def test_signature_on_partial(self): from functools import partial - Parameter = inspect.Parameter - def test(): pass @@ -2988,8 +2987,6 @@ def test(a, b, c:int) -> 42: ((('c', ..., int, "positional_or_keyword"),), 42)) - psig = inspect.signature(partial(partial(test, 1), 2)) - def foo(a): return a _foo = partial(partial(foo, a=10), a=20) @@ -4153,8 +4150,6 @@ def test(a, *args, b, z=100, **kwargs): self.assertEqual(ba.args, (10, 20)) def test_signature_bind_positional_only(self): - P = inspect.Parameter - def test(a_po, b_po, c_po=3, /, foo=42, *, bar=50, **kwargs): return a_po, b_po, c_po, foo, bar, kwargs @@ -4578,7 +4573,6 @@ def test_qualname_source(self): self.assertEqual(err, b'') def test_builtins(self): - module = importlib.import_module('unittest') _, out, err = assert_python_failure('-m', 'inspect', 'sys') lines = err.decode().splitlines() From webhook-mailer at python.org Sat Apr 15 17:15:52 2023 From: webhook-mailer at python.org (miss-islington) Date: Sat, 15 Apr 2023 21:15:52 -0000 Subject: [Python-checkins] gh-103553: Improve `test_inspect`: add more assertions, remove unused (GH-103554) Message-ID: https://github.com/python/cpython/commit/9f3f109dd2061159ca15552ede52c2d9b452293a commit: 9f3f109dd2061159ca15552ede52c2d9b452293a branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-15T14:15:45-07:00 summary: gh-103553: Improve `test_inspect`: add more assertions, remove unused (GH-103554) (cherry picked from commit 4fe1c4b97e39429abbb9c2117fe40f585de00887) Co-authored-by: Nikita Sobolev files: M Lib/test/test_inspect.py diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index a6507c7386a2..9f597e295445 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1761,8 +1761,7 @@ def test_errors(self): self.assertEqualException(f, '2, 3, 4') self.assertEqualException(f, '1, 2, 3, a=1') self.assertEqualException(f, '2, 3, 4, c=5') - # XXX: success of this one depends on dict order - ## self.assertEqualException(f, '2, 3, 4, a=1, c=5') + self.assertEqualException(f, '2, 3, 4, a=1, c=5') # f got an unexpected keyword argument self.assertEqualException(f, 'c=2') self.assertEqualException(f, '2, c=3') @@ -1773,17 +1772,19 @@ def test_errors(self): self.assertEqualException(f, '1, a=2') self.assertEqualException(f, '1, **{"a":2}') self.assertEqualException(f, '1, 2, b=3') - # XXX: Python inconsistency - # - for functions and bound methods: unexpected keyword 'c' - # - for unbound methods: multiple values for keyword 'a' - #self.assertEqualException(f, '1, c=3, a=2') + self.assertEqualException(f, '1, c=3, a=2') # issue11256: f3 = self.makeCallable('**c') self.assertEqualException(f3, '1, 2') self.assertEqualException(f3, '1, 2, a=1, b=2') f4 = self.makeCallable('*, a, b=0') - self.assertEqualException(f3, '1, 2') - self.assertEqualException(f3, '1, 2, a=1, b=2') + self.assertEqualException(f4, '1, 2') + self.assertEqualException(f4, '1, 2, a=1, b=2') + self.assertEqualException(f4, 'a=1, a=3') + self.assertEqualException(f4, 'a=1, c=3') + self.assertEqualException(f4, 'a=1, a=3, b=4') + self.assertEqualException(f4, 'a=1, b=2, a=3, b=4') + self.assertEqualException(f4, 'a=1, a=2, a=3, b=4') # issue #20816: getcallargs() fails to iterate over non-existent # kwonlydefaults and raises a wrong TypeError @@ -2710,8 +2711,6 @@ def foo(cls, *, arg): def test_signature_on_partial(self): from functools import partial - Parameter = inspect.Parameter - def test(): pass @@ -2826,8 +2825,6 @@ def test(a, b, c:int) -> 42: ((('c', ..., int, "positional_or_keyword"),), 42)) - psig = inspect.signature(partial(partial(test, 1), 2)) - def foo(a): return a _foo = partial(partial(foo, a=10), a=20) @@ -3958,8 +3955,6 @@ def test(a, *args, b, z=100, **kwargs): self.assertEqual(ba.args, (10, 20)) def test_signature_bind_positional_only(self): - P = inspect.Parameter - def test(a_po, b_po, c_po=3, /, foo=42, *, bar=50, **kwargs): return a_po, b_po, c_po, foo, bar, kwargs @@ -4392,7 +4387,6 @@ def test_qualname_source(self): self.assertEqual(err, b'') def test_builtins(self): - module = importlib.import_module('unittest') _, out, err = assert_python_failure('-m', 'inspect', 'sys') lines = err.decode().splitlines() From webhook-mailer at python.org Sat Apr 15 23:57:44 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Sun, 16 Apr 2023 03:57:44 -0000 Subject: [Python-checkins] gh-103527: Add multibytecodec.h as make dep for _codecs_* (#103567) Message-ID: https://github.com/python/cpython/commit/a210cac77649a18bf0eb7354c9187ec91ccb078a commit: a210cac77649a18bf0eb7354c9187ec91ccb078a branch: main author: Erlend E. Aasland committer: erlend-aasland date: 2023-04-16T05:57:30+02:00 summary: gh-103527: Add multibytecodec.h as make dep for _codecs_* (#103567) files: M Makefile.pre.in diff --git a/Makefile.pre.in b/Makefile.pre.in index a4633caba305..a58397f21f9b 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2662,12 +2662,14 @@ MODULE__SOCKET_DEPS=$(srcdir)/Modules/socketmodule.h $(srcdir)/Modules/addrinfo. MODULE__SSL_DEPS=$(srcdir)/Modules/_ssl.h $(srcdir)/Modules/_ssl/cert.c $(srcdir)/Modules/_ssl/debughelpers.c $(srcdir)/Modules/_ssl/misc.c $(srcdir)/Modules/_ssl_data.h $(srcdir)/Modules/_ssl_data_111.h $(srcdir)/Modules/_ssl_data_300.h $(srcdir)/Modules/socketmodule.h MODULE__TESTCAPI_DEPS=$(srcdir)/Modules/_testcapi/testcapi_long.h $(srcdir)/Modules/_testcapi/parts.h MODULE__SQLITE3_DEPS=$(srcdir)/Modules/_sqlite/connection.h $(srcdir)/Modules/_sqlite/cursor.h $(srcdir)/Modules/_sqlite/microprotocols.h $(srcdir)/Modules/_sqlite/module.h $(srcdir)/Modules/_sqlite/prepare_protocol.h $(srcdir)/Modules/_sqlite/row.h $(srcdir)/Modules/_sqlite/util.h -MODULE__CODECS_CN_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_cn.h $(srcdir)/Modules/cjkcodecs/cjkcodecs.h -MODULE__CODECS_HK_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_hk.h $(srcdir)/Modules/cjkcodecs/cjkcodecs.h -MODULE__CODECS_ISO2022_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_jisx0213_pair.h $(srcdir)/Modules/cjkcodecs/cjkcodecs.h $(srcdir)/Modules/cjkcodecs/alg_jisx0201.h $(srcdir)/Modules/cjkcodecs/emu_jisx0213_2000.h -MODULE__CODECS_JP_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_jisx0213_pair.h $(srcdir)/Modules/cjkcodecs/cjkcodecs.h $(srcdir)/Modules/cjkcodecs/alg_jisx0201.h $(srcdir)/Modules/cjkcodecs/emu_jisx0213_2000.h $(srcdir)/Modules/cjkcodecs/mappings_jp.h -MODULE__CODECS_KR_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_kr.h $(srcdir)/Modules/cjkcodecs/cjkcodecs.h -MODULE__CODECS_TW_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_tw.h $(srcdir)/Modules/cjkcodecs/cjkcodecs.h + +CODECS_COMMON_HEADERS=$(srcdir)/Modules/cjkcodecs/multibytecodec.h $(srcdir)/Modules/cjkcodecs/cjkcodecs.h +MODULE__CODECS_CN_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_cn.h $(CODECS_COMMON_HEADERS) +MODULE__CODECS_HK_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_hk.h $(CODECS_COMMON_HEADERS) +MODULE__CODECS_ISO2022_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_jisx0213_pair.h $(srcdir)/Modules/cjkcodecs/alg_jisx0201.h $(srcdir)/Modules/cjkcodecs/emu_jisx0213_2000.h $(CODECS_COMMON_HEADERS) +MODULE__CODECS_JP_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_jisx0213_pair.h $(srcdir)/Modules/cjkcodecs/alg_jisx0201.h $(srcdir)/Modules/cjkcodecs/emu_jisx0213_2000.h $(srcdir)/Modules/cjkcodecs/mappings_jp.h $(CODECS_COMMON_HEADERS) +MODULE__CODECS_KR_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_kr.h $(CODECS_COMMON_HEADERS) +MODULE__CODECS_TW_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_tw.h $(CODECS_COMMON_HEADERS) MODULE__MULTIBYTECODEC_DEPS=$(srcdir)/Modules/cjkcodecs/multibytecodec.h # IF YOU PUT ANYTHING HERE IT WILL GO AWAY From webhook-mailer at python.org Sun Apr 16 18:19:51 2023 From: webhook-mailer at python.org (giampaolo) Date: Sun, 16 Apr 2023 22:19:51 -0000 Subject: [Python-checkins] gh-48330: address review comments to PR-12271 (#103209) Message-ID: https://github.com/python/cpython/commit/ff3303e49c13495d8d9cf1dc0cf0624bbda1d3ae commit: ff3303e49c13495d8d9cf1dc0cf0624bbda1d3ae branch: main author: Giampaolo Rodola committer: giampaolo date: 2023-04-17T00:19:44+02:00 summary: gh-48330: address review comments to PR-12271 (#103209) address review comments to PR-12271 Signed-off-by: Giampaolo Rodola files: M Doc/library/unittest.rst M Lib/test/test_unittest/test_runner.py M Lib/unittest/result.py diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index d1a977fd7da6..a7c74cfa4fb4 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -2191,10 +2191,6 @@ Loading and running tests .. versionadded:: 3.12 Added *durations* keyword argument. - .. versionchanged:: 3.12 - Subclasses should accept ``**kwargs`` to ensure compatibility as the - interface changes. - .. data:: defaultTestLoader Instance of the :class:`TestLoader` class intended to be shared. If no diff --git a/Lib/test/test_unittest/test_runner.py b/Lib/test/test_unittest/test_runner.py index 1ce42a106c58..ceb4c8acde53 100644 --- a/Lib/test/test_unittest/test_runner.py +++ b/Lib/test/test_unittest/test_runner.py @@ -1367,7 +1367,7 @@ def testSpecifiedStreamUsed(self): self.assertTrue(runner.stream.stream is f) def test_durations(self): - def run(test, expect_durations): + def run(test, *, expect_durations=True): stream = BufferedWriter() runner = unittest.TextTestRunner(stream=stream, durations=5, verbosity=2) result = runner.run(test) @@ -1389,21 +1389,21 @@ class Foo(unittest.TestCase): def test_1(self): pass - run(Foo('test_1'), True) + run(Foo('test_1'), expect_durations=True) # failure class Foo(unittest.TestCase): def test_1(self): self.assertEqual(0, 1) - run(Foo('test_1'), True) + run(Foo('test_1'), expect_durations=True) # error class Foo(unittest.TestCase): def test_1(self): 1 / 0 - run(Foo('test_1'), True) + run(Foo('test_1'), expect_durations=True) # error in setUp and tearDown @@ -1414,7 +1414,7 @@ def setUp(self): def test_1(self): pass - run(Foo('test_1'), True) + run(Foo('test_1'), expect_durations=True) # skip (expect no durations) class Foo(unittest.TestCase): @@ -1422,7 +1422,7 @@ class Foo(unittest.TestCase): def test_1(self): pass - run(Foo('test_1'), False) + run(Foo('test_1'), expect_durations=False) diff --git a/Lib/unittest/result.py b/Lib/unittest/result.py index fa9bea47c888..7757dba9670b 100644 --- a/Lib/unittest/result.py +++ b/Lib/unittest/result.py @@ -159,7 +159,11 @@ def addUnexpectedSuccess(self, test): self.unexpectedSuccesses.append(test) def addDuration(self, test, elapsed): - """Called when a test finished to run, regardless of its outcome.""" + """Called when a test finished to run, regardless of its outcome. + *test* is the test case corresponding to the test method. + *elapsed* is the time represented in seconds, and it includes the + execution of cleanup functions. + """ # support for a TextTestRunner using an old TestResult class if hasattr(self, "collectedDurations"): self.collectedDurations.append((test, elapsed)) From webhook-mailer at python.org Sun Apr 16 19:09:59 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 16 Apr 2023 23:09:59 -0000 Subject: [Python-checkins] GH-83893: Cross reference env. vars and -X command line options (GH-103414) Message-ID: https://github.com/python/cpython/commit/4c4ef50ec2c6a75f8744bc12a041605d3cd4b48e commit: 4c4ef50ec2c6a75f8744bc12a041605d3cd4b48e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-16T16:09:50-07:00 summary: GH-83893: Cross reference env. vars and -X command line options (GH-103414) (cherry picked from commit d65ed693a8a13a2a7f9b201bda1224d6ae5fcf0e) Co-authored-by: Furkan Onder Co-authored-by: Erlend E. Aasland files: M Doc/using/cmdline.rst diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 2a69ef8f854d..01f3af39173b 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -492,7 +492,8 @@ Miscellaneous options Reserved for various implementation-specific options. CPython currently defines the following possible values: - * ``-X faulthandler`` to enable :mod:`faulthandler`; + * ``-X faulthandler`` to enable :mod:`faulthandler`. + See also :envvar:`PYTHONFAULTHANDLER`. * ``-X showrefcount`` to output the total reference count and number of used memory blocks when the program finishes or after each statement in the interactive interpreter. This only works on :ref:`debug builds @@ -500,8 +501,9 @@ Miscellaneous options * ``-X tracemalloc`` to start tracing Python memory allocations using the :mod:`tracemalloc` module. By default, only the most recent frame is stored in a traceback of a trace. Use ``-X tracemalloc=NFRAME`` to start - tracing with a traceback limit of *NFRAME* frames. See the - :func:`tracemalloc.start` for more information. + tracing with a traceback limit of *NFRAME* frames. + See :func:`tracemalloc.start` and :envvar:`PYTHONTRACEMALLOC` + for more information. * ``-X int_max_str_digits`` configures the :ref:`integer string conversion length limitation `. See also :envvar:`PYTHONINTMAXSTRDIGITS`. @@ -516,6 +518,7 @@ Miscellaneous options * ``-X utf8`` enables the :ref:`Python UTF-8 Mode `. ``-X utf8=0`` explicitly disables :ref:`Python UTF-8 Mode ` (even when it would otherwise activate automatically). + See also :envvar:`PYTHONUTF8`. * ``-X pycache_prefix=PATH`` enables writing ``.pyc`` files to a parallel tree rooted at the given directory instead of to the code tree. See also :envvar:`PYTHONPYCACHEPREFIX`. @@ -847,7 +850,9 @@ conflict. Python memory allocations using the :mod:`tracemalloc` module. The value of the variable is the maximum number of frames stored in a traceback of a trace. For example, ``PYTHONTRACEMALLOC=1`` stores only the most recent - frame. See the :func:`tracemalloc.start` for more information. + frame. + See the :func:`tracemalloc.start` function for more information. + This is equivalent to setting the :option:`-X` ``tracemalloc`` option. .. versionadded:: 3.4 @@ -855,8 +860,8 @@ conflict. .. envvar:: PYTHONPROFILEIMPORTTIME If this environment variable is set to a non-empty string, Python will - show how long each import takes. This is exactly equivalent to setting - ``-X importtime`` on the command line. + show how long each import takes. + This is equivalent to setting the :option:`-X` ``importtime`` option. .. versionadded:: 3.7 @@ -998,6 +1003,7 @@ conflict. If this environment variable is set to a non-empty string, enable :ref:`Python Development Mode `, introducing additional runtime checks that are too expensive to be enabled by default. + This is equivalent to setting the :option:`-X` ``dev`` option. .. versionadded:: 3.7 From webhook-mailer at python.org Sun Apr 16 20:41:35 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Mon, 17 Apr 2023 00:41:35 -0000 Subject: [Python-checkins] gh-103583: Add codecs and maps to _codecs_* module state (#103540) Message-ID: https://github.com/python/cpython/commit/217911ede5d52b02b2e3c9222439e1ea08545291 commit: 217911ede5d52b02b2e3c9222439e1ea08545291 branch: main author: Erlend E. Aasland committer: erlend-aasland date: 2023-04-17T02:41:25+02:00 summary: gh-103583: Add codecs and maps to _codecs_* module state (#103540) files: M Modules/cjkcodecs/_codecs_cn.c M Modules/cjkcodecs/_codecs_hk.c M Modules/cjkcodecs/_codecs_iso2022.c M Modules/cjkcodecs/_codecs_jp.c M Modules/cjkcodecs/_codecs_kr.c M Modules/cjkcodecs/_codecs_tw.c M Modules/cjkcodecs/cjkcodecs.h M Modules/cjkcodecs/multibytecodec.c M Tools/c-analyzer/cpython/globals-to-fix.tsv diff --git a/Modules/cjkcodecs/_codecs_cn.c b/Modules/cjkcodecs/_codecs_cn.c index 8a62f7e257c6..e2c7908c9bb2 100644 --- a/Modules/cjkcodecs/_codecs_cn.c +++ b/Modules/cjkcodecs/_codecs_cn.c @@ -453,14 +453,14 @@ DECODER(hz) } -BEGIN_MAPPINGS_LIST +BEGIN_MAPPINGS_LIST(4) MAPPING_DECONLY(gb2312) MAPPING_DECONLY(gbkext) MAPPING_ENCONLY(gbcommon) MAPPING_ENCDEC(gb18030ext) END_MAPPINGS_LIST -BEGIN_CODECS_LIST +BEGIN_CODECS_LIST(4) CODEC_STATELESS(gb2312) CODEC_STATELESS(gbk) CODEC_STATELESS(gb18030) diff --git a/Modules/cjkcodecs/_codecs_hk.c b/Modules/cjkcodecs/_codecs_hk.c index 4f21569a0ce7..43593b873733 100644 --- a/Modules/cjkcodecs/_codecs_hk.c +++ b/Modules/cjkcodecs/_codecs_hk.c @@ -177,14 +177,13 @@ DECODER(big5hkscs) return 0; } - -BEGIN_MAPPINGS_LIST +BEGIN_MAPPINGS_LIST(3) MAPPING_DECONLY(big5hkscs) MAPPING_ENCONLY(big5hkscs_bmp) MAPPING_ENCONLY(big5hkscs_nonbmp) END_MAPPINGS_LIST -BEGIN_CODECS_LIST +BEGIN_CODECS_LIST(1) CODEC_STATELESS_WINIT(big5hkscs) END_CODECS_LIST diff --git a/Modules/cjkcodecs/_codecs_iso2022.c b/Modules/cjkcodecs/_codecs_iso2022.c index 7394cf67e0e7..cf34752e16a5 100644 --- a/Modules/cjkcodecs/_codecs_iso2022.c +++ b/Modules/cjkcodecs/_codecs_iso2022.c @@ -1119,18 +1119,19 @@ static const struct iso2022_designation iso2022_jp_ext_designations[] = { CONFIGDEF(jp_ext, NO_SHIFT | USE_JISX0208_EXT) -BEGIN_MAPPINGS_LIST +BEGIN_MAPPINGS_LIST(0) /* no mapping table here */ END_MAPPINGS_LIST -#define ISO2022_CODEC(variation) { \ +#define ISO2022_CODEC(variation) \ +NEXT_CODEC = (MultibyteCodec){ \ "iso2022_" #variation, \ &iso2022_##variation##_config, \ iso2022_codec_init, \ _STATEFUL_METHODS(iso2022) \ -}, +}; -BEGIN_CODECS_LIST +BEGIN_CODECS_LIST(7) ISO2022_CODEC(kr) ISO2022_CODEC(jp) ISO2022_CODEC(jp_1) diff --git a/Modules/cjkcodecs/_codecs_jp.c b/Modules/cjkcodecs/_codecs_jp.c index 3a332953b957..7a8b78a23592 100644 --- a/Modules/cjkcodecs/_codecs_jp.c +++ b/Modules/cjkcodecs/_codecs_jp.c @@ -733,7 +733,7 @@ DECODER(shift_jis_2004) } -BEGIN_MAPPINGS_LIST +BEGIN_MAPPINGS_LIST(11) MAPPING_DECONLY(jisx0208) MAPPING_DECONLY(jisx0212) MAPPING_ENCONLY(jisxcommon) @@ -747,14 +747,19 @@ BEGIN_MAPPINGS_LIST MAPPING_ENCDEC(cp932ext) END_MAPPINGS_LIST -BEGIN_CODECS_LIST +#define CODEC_CUSTOM(NAME, N, METH) \ + NEXT_CODEC = (MultibyteCodec){NAME, (void *)N, NULL, _STATELESS_METHODS(METH)}; + +BEGIN_CODECS_LIST(7) CODEC_STATELESS(shift_jis) CODEC_STATELESS(cp932) CODEC_STATELESS(euc_jp) CODEC_STATELESS(shift_jis_2004) CODEC_STATELESS(euc_jis_2004) - { "euc_jisx0213", (void *)2000, NULL, _STATELESS_METHODS(euc_jis_2004) }, - { "shift_jisx0213", (void *)2000, NULL, _STATELESS_METHODS(shift_jis_2004) }, + CODEC_CUSTOM("euc_jisx0213", 2000, euc_jis_2004) + CODEC_CUSTOM("shift_jisx0213", 2000, shift_jis_2004) END_CODECS_LIST +#undef CODEC_CUSTOM + I_AM_A_MODULE_FOR(jp) diff --git a/Modules/cjkcodecs/_codecs_kr.c b/Modules/cjkcodecs/_codecs_kr.c index 72641e495af0..fd9a9fd92db1 100644 --- a/Modules/cjkcodecs/_codecs_kr.c +++ b/Modules/cjkcodecs/_codecs_kr.c @@ -453,13 +453,13 @@ DECODER(johab) #undef FILL -BEGIN_MAPPINGS_LIST +BEGIN_MAPPINGS_LIST(3) MAPPING_DECONLY(ksx1001) MAPPING_ENCONLY(cp949) MAPPING_DECONLY(cp949ext) END_MAPPINGS_LIST -BEGIN_CODECS_LIST +BEGIN_CODECS_LIST(3) CODEC_STATELESS(euc_kr) CODEC_STATELESS(cp949) CODEC_STATELESS(johab) diff --git a/Modules/cjkcodecs/_codecs_tw.c b/Modules/cjkcodecs/_codecs_tw.c index 722b26b128a7..3e4409914144 100644 --- a/Modules/cjkcodecs/_codecs_tw.c +++ b/Modules/cjkcodecs/_codecs_tw.c @@ -130,12 +130,12 @@ DECODER(cp950) -BEGIN_MAPPINGS_LIST +BEGIN_MAPPINGS_LIST(2) MAPPING_ENCDEC(big5) MAPPING_ENCDEC(cp950ext) END_MAPPINGS_LIST -BEGIN_CODECS_LIST +BEGIN_CODECS_LIST(2) CODEC_STATELESS(big5) CODEC_STATELESS(cp950) END_CODECS_LIST diff --git a/Modules/cjkcodecs/cjkcodecs.h b/Modules/cjkcodecs/cjkcodecs.h index d9aeec2ff40b..646a9fd255ce 100644 --- a/Modules/cjkcodecs/cjkcodecs.h +++ b/Modules/cjkcodecs/cjkcodecs.h @@ -60,8 +60,20 @@ struct pair_encodemap { DBCHAR code; }; -static const MultibyteCodec *codec_list; -static const struct dbcs_map *mapping_list; +typedef struct { + int num_mappings; + int num_codecs; + struct dbcs_map *mapping_list; + MultibyteCodec *codec_list; +} cjkcodecs_module_state; + +static inline cjkcodecs_module_state * +get_module_state(PyObject *mod) +{ + void *state = PyModule_GetState(mod); + assert(state != NULL); + return (cjkcodecs_module_state *)state; +} #define CODEC_INIT(encoding) \ static int encoding##_codec_init(const void *config) @@ -202,16 +214,42 @@ static const struct dbcs_map *mapping_list; #define TRYMAP_DEC(charset, assi, c1, c2) \ _TRYMAP_DEC(&charset##_decmap[c1], assi, c2) -#define BEGIN_MAPPINGS_LIST static const struct dbcs_map _mapping_list[] = { -#define MAPPING_ENCONLY(enc) {#enc, (void*)enc##_encmap, NULL}, -#define MAPPING_DECONLY(enc) {#enc, NULL, (void*)enc##_decmap}, -#define MAPPING_ENCDEC(enc) {#enc, (void*)enc##_encmap, (void*)enc##_decmap}, -#define END_MAPPINGS_LIST \ - {"", NULL, NULL} }; \ - static const struct dbcs_map *mapping_list = \ - (const struct dbcs_map *)_mapping_list; +#define BEGIN_MAPPINGS_LIST(NUM) \ +static int \ +add_mappings(cjkcodecs_module_state *st) \ +{ \ + int idx = 0; \ + (void)idx; \ + st->num_mappings = NUM; \ + st->mapping_list = PyMem_Calloc(NUM, sizeof(struct dbcs_map)); \ + if (st->mapping_list == NULL) { \ + return -1; \ + } + +#define MAPPING_ENCONLY(enc) \ + st->mapping_list[idx++] = (struct dbcs_map){#enc, (void*)enc##_encmap, NULL}; +#define MAPPING_DECONLY(enc) \ + st->mapping_list[idx++] = (struct dbcs_map){#enc, NULL, (void*)enc##_decmap}; +#define MAPPING_ENCDEC(enc) \ + st->mapping_list[idx++] = (struct dbcs_map){#enc, (void*)enc##_encmap, (void*)enc##_decmap}; + +#define END_MAPPINGS_LIST \ + assert(st->num_mappings == idx); \ + return 0; \ +} + +#define BEGIN_CODECS_LIST(NUM) \ +static int \ +add_codecs(cjkcodecs_module_state *st) \ +{ \ + int idx = 0; \ + (void)idx; \ + st->num_codecs = NUM; \ + st->codec_list = PyMem_Calloc(NUM, sizeof(MultibyteCodec)); \ + if (st->codec_list == NULL) { \ + return -1; \ + } -#define BEGIN_CODECS_LIST static const MultibyteCodec _codec_list[] = { #define _STATEFUL_METHODS(enc) \ enc##_encode, \ enc##_encode_init, \ @@ -222,23 +260,21 @@ static const struct dbcs_map *mapping_list; #define _STATELESS_METHODS(enc) \ enc##_encode, NULL, NULL, \ enc##_decode, NULL, NULL, -#define CODEC_STATEFUL(enc) { \ - #enc, NULL, NULL, \ - _STATEFUL_METHODS(enc) \ -}, -#define CODEC_STATELESS(enc) { \ - #enc, NULL, NULL, \ - _STATELESS_METHODS(enc) \ -}, -#define CODEC_STATELESS_WINIT(enc) { \ - #enc, NULL, \ - enc##_codec_init, \ - _STATELESS_METHODS(enc) \ -}, -#define END_CODECS_LIST \ - {"", NULL,} }; \ - static const MultibyteCodec *codec_list = \ - (const MultibyteCodec *)_codec_list; + +#define NEXT_CODEC \ + st->codec_list[idx++] + +#define CODEC_STATEFUL(enc) \ + NEXT_CODEC = (MultibyteCodec){#enc, NULL, NULL, _STATEFUL_METHODS(enc)}; +#define CODEC_STATELESS(enc) \ + NEXT_CODEC = (MultibyteCodec){#enc, NULL, NULL, _STATELESS_METHODS(enc)}; +#define CODEC_STATELESS_WINIT(enc) \ + NEXT_CODEC = (MultibyteCodec){#enc, NULL, enc##_codec_init, _STATELESS_METHODS(enc)}; + +#define END_CODECS_LIST \ + assert(st->num_codecs == idx); \ + return 0; \ +} @@ -249,53 +285,70 @@ getmultibytecodec(void) } static PyObject * -getcodec(PyObject *self, PyObject *encoding) +_getcodec(const MultibyteCodec *codec) { - PyObject *codecobj, *r, *cofunc; - const MultibyteCodec *codec; - const char *enc; - - if (!PyUnicode_Check(encoding)) { - PyErr_SetString(PyExc_TypeError, - "encoding name must be a string."); + PyObject *cofunc = getmultibytecodec(); + if (cofunc == NULL) { return NULL; } - enc = PyUnicode_AsUTF8(encoding); - if (enc == NULL) - return NULL; - cofunc = getmultibytecodec(); - if (cofunc == NULL) + PyObject *codecobj = PyCapsule_New((void *)codec, + PyMultibyteCodec_CAPSULE_NAME, + NULL); + if (codecobj == NULL) { + Py_DECREF(cofunc); return NULL; + } - for (codec = codec_list; codec->encoding[0]; codec++) - if (strcmp(codec->encoding, enc) == 0) - break; + PyObject *res = PyObject_CallOneArg(cofunc, codecobj); + Py_DECREF(codecobj); + Py_DECREF(cofunc); + return res; +} - if (codec->encoding[0] == '\0') { - PyErr_SetString(PyExc_LookupError, - "no such codec is supported."); +static PyObject * +getcodec(PyObject *self, PyObject *encoding) +{ + if (!PyUnicode_Check(encoding)) { + PyErr_SetString(PyExc_TypeError, + "encoding name must be a string."); return NULL; } - - codecobj = PyCapsule_New((void *)codec, PyMultibyteCodec_CAPSULE_NAME, NULL); - if (codecobj == NULL) + const char *enc = PyUnicode_AsUTF8(encoding); + if (enc == NULL) { return NULL; + } - r = PyObject_CallOneArg(cofunc, codecobj); - Py_DECREF(codecobj); - Py_DECREF(cofunc); + cjkcodecs_module_state *st = get_module_state(self); + for (int i = 0; i < st->num_codecs; i++) { + const MultibyteCodec *codec = &st->codec_list[i]; + if (strcmp(codec->encoding, enc) == 0) { + return _getcodec(codec); + } + } - return r; + PyErr_SetString(PyExc_LookupError, + "no such codec is supported."); + return NULL; } +static int add_mappings(cjkcodecs_module_state *); +static int add_codecs(cjkcodecs_module_state *); static int register_maps(PyObject *module) { - const struct dbcs_map *h; + // Init module state. + cjkcodecs_module_state *st = get_module_state(module); + if (add_mappings(st) < 0) { + return -1; + } + if (add_codecs(st) < 0) { + return -1; + } - for (h = mapping_list; h->charset[0] != '\0'; h++) { + for (int i = 0; i < st->num_mappings; i++) { + const struct dbcs_map *h = &st->mapping_list[i]; char mhname[256] = "__map_"; strcpy(mhname + sizeof("__map_") - 1, h->charset); @@ -394,6 +447,13 @@ _cjk_exec(PyObject *module) return register_maps(module); } +static void +_cjk_free(void *mod) +{ + cjkcodecs_module_state *st = get_module_state((PyObject *)mod); + PyMem_Free(st->mapping_list); + PyMem_Free(st->codec_list); +} static struct PyMethodDef _cjk_methods[] = { {"getcodec", (PyCFunction)getcodec, METH_O, ""}, @@ -409,9 +469,10 @@ static PyModuleDef_Slot _cjk_slots[] = { static struct PyModuleDef _cjk_module = { \ PyModuleDef_HEAD_INIT, \ .m_name = "_codecs_"#loc, \ - .m_size = 0, \ + .m_size = sizeof(cjkcodecs_module_state), \ .m_methods = _cjk_methods, \ .m_slots = _cjk_slots, \ + .m_free = _cjk_free, \ }; \ \ PyMODINIT_FUNC \ diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c index 8564494f6262..55778cdb59e4 100644 --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -19,26 +19,27 @@ typedef struct { PyTypeObject *writer_type; PyTypeObject *multibytecodec_type; PyObject *str_write; -} _multibytecodec_state; +} module_state; -static _multibytecodec_state * -_multibytecodec_get_state(PyObject *module) +static module_state * +get_module_state(PyObject *module) { - _multibytecodec_state *state = PyModule_GetState(module); + module_state *state = PyModule_GetState(module); assert(state != NULL); return state; } static struct PyModuleDef _multibytecodecmodule; -static _multibytecodec_state * -_multibyte_codec_find_state_by_type(PyTypeObject *type) + +static module_state * +find_state_by_def(PyTypeObject *type) { PyObject *module = PyType_GetModuleByDef(type, &_multibytecodecmodule); assert(module != NULL); - return _multibytecodec_get_state(module); + return get_module_state(module); } -#define clinic_get_state() _multibyte_codec_find_state_by_type(type) +#define clinic_get_state() find_state_by_def(type) /*[clinic input] module _multibytecodec class _multibytecodec.MultibyteCodec "MultibyteCodecObject *" "clinic_get_state()->multibytecodec_type" @@ -1040,7 +1041,7 @@ mbiencoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (codec == NULL) goto errorexit; - _multibytecodec_state *state = _multibyte_codec_find_state_by_type(type); + module_state *state = find_state_by_def(type); if (!MultibyteCodec_Check(state, codec)) { PyErr_SetString(PyExc_TypeError, "codec is unexpected type"); goto errorexit; @@ -1315,7 +1316,7 @@ mbidecoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (codec == NULL) goto errorexit; - _multibytecodec_state *state = _multibyte_codec_find_state_by_type(type); + module_state *state = find_state_by_def(type); if (!MultibyteCodec_Check(state, codec)) { PyErr_SetString(PyExc_TypeError, "codec is unexpected type"); goto errorexit; @@ -1630,7 +1631,7 @@ mbstreamreader_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (codec == NULL) goto errorexit; - _multibytecodec_state *state = _multibyte_codec_find_state_by_type(type); + module_state *state = find_state_by_def(type); if (!MultibyteCodec_Check(state, codec)) { PyErr_SetString(PyExc_TypeError, "codec is unexpected type"); goto errorexit; @@ -1735,7 +1736,7 @@ _multibytecodec_MultibyteStreamWriter_write_impl(MultibyteStreamWriterObject *se PyObject *strobj) /*[clinic end generated code: output=68ade3aea26410ac input=199f26f68bd8425a]*/ { - _multibytecodec_state *state = PyType_GetModuleState(cls); + module_state *state = PyType_GetModuleState(cls); assert(state != NULL); if (mbstreamwriter_iwrite(self, strobj, state->str_write)) { return NULL; @@ -1766,7 +1767,7 @@ _multibytecodec_MultibyteStreamWriter_writelines_impl(MultibyteStreamWriterObjec return NULL; } - _multibytecodec_state *state = PyType_GetModuleState(cls); + module_state *state = PyType_GetModuleState(cls); assert(state != NULL); for (i = 0; i < PySequence_Length(lines); i++) { /* length can be changed even within this loop */ @@ -1817,7 +1818,7 @@ _multibytecodec_MultibyteStreamWriter_reset_impl(MultibyteStreamWriterObject *se assert(PyBytes_Check(pwrt)); - _multibytecodec_state *state = PyType_GetModuleState(cls); + module_state *state = PyType_GetModuleState(cls); assert(state != NULL); if (PyBytes_Size(pwrt) > 0) { @@ -1853,7 +1854,7 @@ mbstreamwriter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (codec == NULL) goto errorexit; - _multibytecodec_state *state = _multibyte_codec_find_state_by_type(type); + module_state *state = find_state_by_def(type); if (!MultibyteCodec_Check(state, codec)) { PyErr_SetString(PyExc_TypeError, "codec is unexpected type"); goto errorexit; @@ -1963,7 +1964,7 @@ _multibytecodec___create_codec(PyObject *module, PyObject *arg) if (codec->codecinit != NULL && codec->codecinit(codec->config) != 0) return NULL; - _multibytecodec_state *state = _multibytecodec_get_state(module); + module_state *state = get_module_state(module); self = PyObject_GC_New(MultibyteCodecObject, state->multibytecodec_type); if (self == NULL) return NULL; @@ -1976,7 +1977,7 @@ _multibytecodec___create_codec(PyObject *module, PyObject *arg) static int _multibytecodec_traverse(PyObject *mod, visitproc visit, void *arg) { - _multibytecodec_state *state = _multibytecodec_get_state(mod); + module_state *state = get_module_state(mod); Py_VISIT(state->multibytecodec_type); Py_VISIT(state->encoder_type); Py_VISIT(state->decoder_type); @@ -1988,7 +1989,7 @@ _multibytecodec_traverse(PyObject *mod, visitproc visit, void *arg) static int _multibytecodec_clear(PyObject *mod) { - _multibytecodec_state *state = _multibytecodec_get_state(mod); + module_state *state = get_module_state(mod); Py_CLEAR(state->multibytecodec_type); Py_CLEAR(state->encoder_type); Py_CLEAR(state->decoder_type); @@ -2022,7 +2023,7 @@ _multibytecodec_free(void *mod) static int _multibytecodec_exec(PyObject *mod) { - _multibytecodec_state *state = _multibytecodec_get_state(mod); + module_state *state = get_module_state(mod); state->str_write = PyUnicode_InternFromString("write"); if (state->str_write == NULL) { return -1; @@ -2056,7 +2057,7 @@ static PyModuleDef_Slot _multibytecodec_slots[] = { static struct PyModuleDef _multibytecodecmodule = { .m_base = PyModuleDef_HEAD_INIT, .m_name = "_multibytecodec", - .m_size = sizeof(_multibytecodec_state), + .m_size = sizeof(module_state), .m_methods = _multibytecodec_methods, .m_slots = _multibytecodec_slots, .m_traverse = _multibytecodec_traverse, diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 5c173b1041e3..849fd5d9a1e8 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -506,8 +506,6 @@ Modules/cjkcodecs/_codecs_iso2022.c jisx0208_init initialized - Modules/cjkcodecs/_codecs_iso2022.c jisx0212_init initialized - Modules/cjkcodecs/_codecs_iso2022.c jisx0213_init initialized - Modules/cjkcodecs/_codecs_iso2022.c gb2312_init initialized - -Modules/cjkcodecs/cjkcodecs.h - codec_list - -Modules/cjkcodecs/cjkcodecs.h - mapping_list - Modules/readline.c - libedit_append_replace_history_offset - Modules/readline.c - using_libedit_emulation - Modules/readline.c - libedit_history_start - From webhook-mailer at python.org Sun Apr 16 23:27:01 2023 From: webhook-mailer at python.org (hugovk) Date: Mon, 17 Apr 2023 03:27:01 -0000 Subject: [Python-checkins] Remove `expert-*` from `project-updater` GH workflow (#103579) Message-ID: https://github.com/python/cpython/commit/76933df10afc958b2db2a6bcff7509285fbf5fcf commit: 76933df10afc958b2db2a6bcff7509285fbf5fcf branch: main author: Ezio Melotti committer: hugovk date: 2023-04-17T06:26:22+03:00 summary: Remove `expert-*` from `project-updater` GH workflow (#103579) files: M .github/workflows/project-updater.yml diff --git a/.github/workflows/project-updater.yml b/.github/workflows/project-updater.yml index dde923b26c2a..7574bfc208ff 100644 --- a/.github/workflows/project-updater.yml +++ b/.github/workflows/project-updater.yml @@ -20,8 +20,6 @@ jobs: # if an issue has any of these labels, it will be added # to the corresponding project - { project: 2, label: "release-blocker, deferred-blocker" } - - { project: 3, label: expert-subinterpreters } - - { project: 29, label: expert-asyncio } - { project: 32, label: sprint } steps: From webhook-mailer at python.org Mon Apr 17 10:14:26 2023 From: webhook-mailer at python.org (corona10) Date: Mon, 17 Apr 2023 14:14:26 -0000 Subject: [Python-checkins] gh-101525: Fix make test if the --enable-bolt enabled (gh-103574) Message-ID: https://github.com/python/cpython/commit/5d9762e7cf90444b03b43262be8001ff83401aac commit: 5d9762e7cf90444b03b43262be8001ff83401aac branch: main author: Dong-hee Na committer: corona10 date: 2023-04-17T23:14:18+09:00 summary: gh-101525: Fix make test if the --enable-bolt enabled (gh-103574) files: M Makefile.pre.in M configure M configure.ac diff --git a/Makefile.pre.in b/Makefile.pre.in index a58397f21f9b..582310807d05 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -38,6 +38,7 @@ CC= @CC@ CXX= @CXX@ LINKCC= @LINKCC@ AR= @AR@ +READELF= @READELF@ SOABI= @SOABI@ LDVERSION= @LDVERSION@ LIBPYTHON= @LIBPYTHON@ @@ -670,13 +671,18 @@ profile-opt: profile-run-stamp bolt-opt: @PREBOLT_RULE@ rm -f *.fdata - @LLVM_BOLT@ ./$(BUILDPYTHON) -instrument -instrumentation-file-append-pid -instrumentation-file=$(abspath $(BUILDPYTHON).bolt) -o $(BUILDPYTHON).bolt_inst - ./$(BUILDPYTHON).bolt_inst $(PROFILE_TASK) || true - @MERGE_FDATA@ $(BUILDPYTHON).*.fdata > $(BUILDPYTHON).fdata - @LLVM_BOLT@ ./$(BUILDPYTHON) -o $(BUILDPYTHON).bolt -data=$(BUILDPYTHON).fdata -update-debug-sections -reorder-blocks=ext-tsp -reorder-functions=hfsort+ -split-functions -icf=1 -inline-all -split-eh -reorder-functions-use-hot-size -peepholes=none -jump-tables=aggressive -inline-ap -indirect-call-promotion=all -dyno-stats -use-gnu-stack -frame-opt=hot - rm -f *.fdata - rm -f $(BUILDPYTHON).bolt_inst - mv $(BUILDPYTHON).bolt $(BUILDPYTHON) + @if $(READELF) -p .note.bolt_info $(BUILDPYTHON) | grep BOLT > /dev/null; then\ + echo "skip: $(BUILDPYTHON) is already BOLTed."; \ + else \ + @LLVM_BOLT@ ./$(BUILDPYTHON) -instrument -instrumentation-file-append-pid -instrumentation-file=$(abspath $(BUILDPYTHON).bolt) -o $(BUILDPYTHON).bolt_inst; \ + ./$(BUILDPYTHON).bolt_inst $(PROFILE_TASK) || true; \ + @MERGE_FDATA@ $(BUILDPYTHON).*.fdata > $(BUILDPYTHON).fdata; \ + @LLVM_BOLT@ ./$(BUILDPYTHON) -o $(BUILDPYTHON).bolt -data=$(BUILDPYTHON).fdata -update-debug-sections -reorder-blocks=ext-tsp -reorder-functions=hfsort+ -split-functions -icf=1 -inline-all -split-eh -reorder-functions-use-hot-size -peepholes=none -jump-tables=aggressive -inline-ap -indirect-call-promotion=all -dyno-stats -use-gnu-stack -frame-opt=hot; \ + rm -f *.fdata; \ + rm -f $(BUILDPYTHON).bolt_inst; \ + mv $(BUILDPYTHON).bolt $(BUILDPYTHON); \ + fi + # Compile and run with gcov .PHONY=coverage coverage-lcov coverage-report diff --git a/configure b/configure index 4ae8258438e6..8133d47f6135 100755 --- a/configure +++ b/configure @@ -892,6 +892,8 @@ PGO_PROF_USE_FLAG PGO_PROF_GEN_FLAG MERGE_FDATA LLVM_BOLT +ac_ct_READELF +READELF PREBOLT_RULE LLVM_AR_FOUND LLVM_AR @@ -7916,6 +7918,112 @@ if test "$Py_BOLT" = 'true' ; then DEF_MAKE_ALL_RULE="bolt-opt" DEF_MAKE_RULE="build_all" + + if test -n "$ac_tool_prefix"; then + for ac_prog in readelf + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_READELF+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$READELF"; then + ac_cv_prog_READELF="$READELF" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_READELF="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +READELF=$ac_cv_prog_READELF +if test -n "$READELF"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $READELF" >&5 +$as_echo "$READELF" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$READELF" && break + done +fi +if test -z "$READELF"; then + ac_ct_READELF=$READELF + for ac_prog in readelf +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_READELF+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_READELF"; then + ac_cv_prog_ac_ct_READELF="$ac_ct_READELF" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_READELF="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_READELF=$ac_cv_prog_ac_ct_READELF +if test -n "$ac_ct_READELF"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_READELF" >&5 +$as_echo "$ac_ct_READELF" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_READELF" && break +done + + if test "x$ac_ct_READELF" = x; then + READELF=""notfound"" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + READELF=$ac_ct_READELF + fi +fi + + if test "$READELF" == "notfound" + then + as_fn_error $? "readelf is required for a --enable-bolt build but could not be found." "$LINENO" 5 + fi + # -fno-reorder-blocks-and-partition is required for bolt to work. # Possibly GCC only. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fno-reorder-blocks-and-partition" >&5 diff --git a/configure.ac b/configure.ac index 4d9eb46f5ce7..3f20d8980d8a 100644 --- a/configure.ac +++ b/configure.ac @@ -1938,6 +1938,13 @@ if test "$Py_BOLT" = 'true' ; then DEF_MAKE_ALL_RULE="bolt-opt" DEF_MAKE_RULE="build_all" + AC_SUBST(READELF) + AC_CHECK_TOOLS(READELF, [readelf], "notfound") + if test "$READELF" == "notfound" + then + AC_MSG_ERROR([readelf is required for a --enable-bolt build but could not be found.]) + fi + # -fno-reorder-blocks-and-partition is required for bolt to work. # Possibly GCC only. AX_CHECK_COMPILE_FLAG([-fno-reorder-blocks-and-partition],[ From webhook-mailer at python.org Mon Apr 17 12:34:38 2023 From: webhook-mailer at python.org (zooba) Date: Mon, 17 Apr 2023 16:34:38 -0000 Subject: [Python-checkins] gh-103088: Ensure POSIX venv scripts always use LF line endings (GH-103591) Message-ID: https://github.com/python/cpython/commit/eb5fd31948e2e379635e17545c18c9ef5d06d3e7 commit: eb5fd31948e2e379635e17545c18c9ef5d06d3e7 branch: main author: Steve Dower committer: zooba date: 2023-04-17T17:33:54+01:00 summary: gh-103088: Ensure POSIX venv scripts always use LF line endings (GH-103591) Also touches the affected files in meaningless ways to ensure they get updated when pulling files: M .gitattributes M Lib/venv/scripts/common/activate M Lib/venv/scripts/posix/activate.csh M Lib/venv/scripts/posix/activate.fish diff --git a/.gitattributes b/.gitattributes index cb1cf8bcc7c8..4ed95069442f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -34,6 +34,7 @@ Lib/test/xmltestdata/* noeol # Shell scripts should have LF even on Windows because of Cygwin Lib/venv/scripts/common/activate text eol=lf +Lib/venv/scripts/posix/* text eol=lf # CRLF files [attr]dos text eol=crlf diff --git a/Lib/venv/scripts/common/activate b/Lib/venv/scripts/common/activate index cb898b39670c..408df5cb93b9 100644 --- a/Lib/venv/scripts/common/activate +++ b/Lib/venv/scripts/common/activate @@ -1,5 +1,5 @@ # This file must be used with "source bin/activate" *from bash* -# you cannot run it directly +# You cannot run it directly deactivate () { # reset old environment variables diff --git a/Lib/venv/scripts/posix/activate.csh b/Lib/venv/scripts/posix/activate.csh index d6f697c55ed8..5e8d66fa9e50 100644 --- a/Lib/venv/scripts/posix/activate.csh +++ b/Lib/venv/scripts/posix/activate.csh @@ -1,5 +1,6 @@ # This file must be used with "source bin/activate.csh" *from csh*. # You cannot run it directly. + # Created by Davide Di Blasi . # Ported to Python 3.3 venv by Andrew Svetlov diff --git a/Lib/venv/scripts/posix/activate.fish b/Lib/venv/scripts/posix/activate.fish index 9aa4446005f4..91ad6442e056 100644 --- a/Lib/venv/scripts/posix/activate.fish +++ b/Lib/venv/scripts/posix/activate.fish @@ -1,5 +1,5 @@ # This file must be used with "source /bin/activate.fish" *from fish* -# (https://fishshell.com/); you cannot run it directly. +# (https://fishshell.com/). You cannot run it directly. function deactivate -d "Exit virtual environment and return to normal shell environment" # reset old environment variables From webhook-mailer at python.org Mon Apr 17 14:30:56 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Mon, 17 Apr 2023 18:30:56 -0000 Subject: [Python-checkins] gh-103092: Isolate winreg (#103250) Message-ID: https://github.com/python/cpython/commit/d83faf7f1ba2de95e98e3eeb5ce9009d9cd62192 commit: d83faf7f1ba2de95e98e3eeb5ce9009d9cd62192 branch: main author: AN Long committer: erlend-aasland date: 2023-04-17T12:30:48-06:00 summary: gh-103092: Isolate winreg (#103250) files: A Misc/NEWS.d/next/Library/2023-04-08-00-48-40.gh-issue-103092.5EFts0.rst M Lib/test/test_winreg.py M Objects/object.c M PC/clinic/winreg.c.h M PC/winreg.c diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py index 769ab67b0f56..924a962781a7 100644 --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -1,11 +1,12 @@ # Test the windows specific win32reg module. # Only win32reg functions not hit here: FlushKey, LoadKey and SaveKey +import gc import os, sys, errno -import unittest -from test.support import import_helper import threading +import unittest from platform import machine, win32_edition +from test.support import cpython_only, import_helper # Do this first so test will be skipped if module doesn't exist import_helper.import_module('winreg', required_on=['win']) @@ -49,6 +50,17 @@ ("Japanese ??", "???", REG_SZ), ] + + at cpython_only +class HeapTypeTests(unittest.TestCase): + def test_have_gc(self): + self.assertTrue(gc.is_tracked(HKEYType)) + + def test_immutable(self): + with self.assertRaisesRegex(TypeError, "immutable"): + HKEYType.foo = "bar" + + class BaseWinregTests(unittest.TestCase): def setUp(self): diff --git a/Misc/NEWS.d/next/Library/2023-04-08-00-48-40.gh-issue-103092.5EFts0.rst b/Misc/NEWS.d/next/Library/2023-04-08-00-48-40.gh-issue-103092.5EFts0.rst new file mode 100644 index 000000000000..0f2108fee763 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-08-00-48-40.gh-issue-103092.5EFts0.rst @@ -0,0 +1 @@ +Adapt the :mod:`winreg` extension module to :pep:`687`. diff --git a/Objects/object.c b/Objects/object.c index 56747fa193e1..e26f737fccd6 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1965,9 +1965,6 @@ PyObject _Py_NotImplementedStruct = { 1, &_PyNotImplemented_Type }; -#ifdef MS_WINDOWS -extern PyTypeObject PyHKEY_Type; -#endif extern PyTypeObject _Py_GenericAliasIterType; extern PyTypeObject _PyMemoryIter_Type; extern PyTypeObject _PyLineIterator; @@ -2018,9 +2015,6 @@ static PyTypeObject* static_types[] = { &PyFunction_Type, &PyGen_Type, &PyGetSetDescr_Type, -#ifdef MS_WINDOWS - &PyHKEY_Type, -#endif &PyInstanceMethod_Type, &PyListIter_Type, &PyListRevIter_Type, diff --git a/PC/clinic/winreg.c.h b/PC/clinic/winreg.c.h index 7a9474301da8..4109c85276f0 100644 --- a/PC/clinic/winreg.c.h +++ b/PC/clinic/winreg.c.h @@ -219,14 +219,14 @@ winreg_ConnectRegistry(PyObject *module, PyObject *const *args, Py_ssize_t nargs _PyArg_BadArgument("ConnectRegistry", "argument 1", "str or None", args[0]); goto exit; } - if (!clinic_HKEY_converter(args[1], &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), args[1], &key)) { goto exit; } _return_value = winreg_ConnectRegistry_impl(module, computer_name, key); if (_return_value == NULL) { goto exit; } - return_value = PyHKEY_FromHKEY(_return_value); + return_value = PyHKEY_FromHKEY(_PyModule_GetState(module), _return_value); exit: /* Cleanup for computer_name */ @@ -275,7 +275,7 @@ winreg_CreateKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("CreateKey", nargs, 2, 2)) { goto exit; } - if (!clinic_HKEY_converter(args[0], &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) { goto exit; } if (args[1] == Py_None) { @@ -295,7 +295,7 @@ winreg_CreateKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (_return_value == NULL) { goto exit; } - return_value = PyHKEY_FromHKEY(_return_value); + return_value = PyHKEY_FromHKEY(_PyModule_GetState(module), _return_value); exit: /* Cleanup for sub_key */ @@ -382,7 +382,7 @@ winreg_CreateKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py if (!args) { goto exit; } - if (!clinic_HKEY_converter(args[0], &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) { goto exit; } if (args[1] == Py_None) { @@ -419,7 +419,7 @@ winreg_CreateKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py if (_return_value == NULL) { goto exit; } - return_value = PyHKEY_FromHKEY(_return_value); + return_value = PyHKEY_FromHKEY(_PyModule_GetState(module), _return_value); exit: /* Cleanup for sub_key */ @@ -466,7 +466,7 @@ winreg_DeleteKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("DeleteKey", nargs, 2, 2)) { goto exit; } - if (!clinic_HKEY_converter(args[0], &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) { goto exit; } if (!PyUnicode_Check(args[1])) { @@ -566,7 +566,7 @@ winreg_DeleteKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py if (!args) { goto exit; } - if (!clinic_HKEY_converter(args[0], &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) { goto exit; } if (!PyUnicode_Check(args[1])) { @@ -634,7 +634,7 @@ winreg_DeleteValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("DeleteValue", nargs, 2, 2)) { goto exit; } - if (!clinic_HKEY_converter(args[0], &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) { goto exit; } if (args[1] == Py_None) { @@ -694,7 +694,7 @@ winreg_EnumKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("EnumKey", nargs, 2, 2)) { goto exit; } - if (!clinic_HKEY_converter(args[0], &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) { goto exit; } index = _PyLong_AsInt(args[1]); @@ -751,7 +751,7 @@ winreg_EnumValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("EnumValue", nargs, 2, 2)) { goto exit; } - if (!clinic_HKEY_converter(args[0], &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) { goto exit; } index = _PyLong_AsInt(args[1]); @@ -839,7 +839,7 @@ winreg_FlushKey(PyObject *module, PyObject *arg) PyObject *return_value = NULL; HKEY key; - if (!clinic_HKEY_converter(arg, &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), arg, &key)) { goto exit; } return_value = winreg_FlushKey_impl(module, key); @@ -898,7 +898,7 @@ winreg_LoadKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("LoadKey", nargs, 3, 3)) { goto exit; } - if (!clinic_HKEY_converter(args[0], &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) { goto exit; } if (!PyUnicode_Check(args[1])) { @@ -999,7 +999,7 @@ winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje if (!args) { goto exit; } - if (!clinic_HKEY_converter(args[0], &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) { goto exit; } if (args[1] == Py_None) { @@ -1036,7 +1036,7 @@ winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje if (_return_value == NULL) { goto exit; } - return_value = PyHKEY_FromHKEY(_return_value); + return_value = PyHKEY_FromHKEY(_PyModule_GetState(module), _return_value); exit: /* Cleanup for sub_key */ @@ -1116,7 +1116,7 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb if (!args) { goto exit; } - if (!clinic_HKEY_converter(args[0], &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) { goto exit; } if (args[1] == Py_None) { @@ -1153,7 +1153,7 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb if (_return_value == NULL) { goto exit; } - return_value = PyHKEY_FromHKEY(_return_value); + return_value = PyHKEY_FromHKEY(_PyModule_GetState(module), _return_value); exit: /* Cleanup for sub_key */ @@ -1193,7 +1193,7 @@ winreg_QueryInfoKey(PyObject *module, PyObject *arg) PyObject *return_value = NULL; HKEY key; - if (!clinic_HKEY_converter(arg, &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), arg, &key)) { goto exit; } return_value = winreg_QueryInfoKey_impl(module, key); @@ -1242,7 +1242,7 @@ winreg_QueryValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("QueryValue", nargs, 2, 2)) { goto exit; } - if (!clinic_HKEY_converter(args[0], &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) { goto exit; } if (args[1] == Py_None) { @@ -1303,7 +1303,7 @@ winreg_QueryValueEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("QueryValueEx", nargs, 2, 2)) { goto exit; } - if (!clinic_HKEY_converter(args[0], &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) { goto exit; } if (args[1] == Py_None) { @@ -1369,7 +1369,7 @@ winreg_SaveKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("SaveKey", nargs, 2, 2)) { goto exit; } - if (!clinic_HKEY_converter(args[0], &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) { goto exit; } if (!PyUnicode_Check(args[1])) { @@ -1438,7 +1438,7 @@ winreg_SetValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("SetValue", nargs, 4, 4)) { goto exit; } - if (!clinic_HKEY_converter(args[0], &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) { goto exit; } if (args[1] == Py_None) { @@ -1542,7 +1542,7 @@ winreg_SetValueEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("SetValueEx", nargs, 5, 5)) { goto exit; } - if (!clinic_HKEY_converter(args[0], &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) { goto exit; } if (args[1] == Py_None) { @@ -1603,7 +1603,7 @@ winreg_DisableReflectionKey(PyObject *module, PyObject *arg) PyObject *return_value = NULL; HKEY key; - if (!clinic_HKEY_converter(arg, &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), arg, &key)) { goto exit; } return_value = winreg_DisableReflectionKey_impl(module, key); @@ -1641,7 +1641,7 @@ winreg_EnableReflectionKey(PyObject *module, PyObject *arg) PyObject *return_value = NULL; HKEY key; - if (!clinic_HKEY_converter(arg, &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), arg, &key)) { goto exit; } return_value = winreg_EnableReflectionKey_impl(module, key); @@ -1677,7 +1677,7 @@ winreg_QueryReflectionKey(PyObject *module, PyObject *arg) PyObject *return_value = NULL; HKEY key; - if (!clinic_HKEY_converter(arg, &key)) { + if (!clinic_HKEY_converter(_PyModule_GetState(module), arg, &key)) { goto exit; } return_value = winreg_QueryReflectionKey_impl(module, key); @@ -1795,4 +1795,4 @@ winreg_QueryReflectionKey(PyObject *module, PyObject *arg) #ifndef WINREG_QUERYREFLECTIONKEY_METHODDEF #define WINREG_QUERYREFLECTIONKEY_METHODDEF #endif /* !defined(WINREG_QUERYREFLECTIONKEY_METHODDEF) */ -/*[clinic end generated code: output=715db416dc1321ee input=a9049054013a1b77]*/ +/*[clinic end generated code: output=15dc2e6c4d4e2ad5 input=a9049054013a1b77]*/ diff --git a/PC/winreg.c b/PC/winreg.c index 15d32e7fcb99..4884125c3609 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -15,15 +15,22 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_object.h" // _PyObject_Init() +#include "pycore_moduleobject.h" #include "structmember.h" // PyMemberDef #include #if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES) -static BOOL PyHKEY_AsHKEY(PyObject *ob, HKEY *pRes, BOOL bNoneOK); -static BOOL clinic_HKEY_converter(PyObject *ob, void *p); -static PyObject *PyHKEY_FromHKEY(HKEY h); -static BOOL PyHKEY_Close(PyObject *obHandle); +typedef struct { + PyTypeObject *PyHKEY_Type; +} winreg_state; + +/* Forward declares */ + +static BOOL PyHKEY_AsHKEY(winreg_state *st, PyObject *ob, HKEY *pRes, BOOL bNoneOK); +static BOOL clinic_HKEY_converter(winreg_state *st, PyObject *ob, void *p); +static PyObject *PyHKEY_FromHKEY(winreg_state *st, HKEY h); +static BOOL PyHKEY_Close(winreg_state *st, PyObject *obHandle); static char errNotAHandle[] = "Object is not a handle"; @@ -35,8 +42,6 @@ static char errNotAHandle[] = "Object is not a handle"; #define PyErr_SetFromWindowsErrWithFunction(rc, fnname) \ PyErr_SetFromWindowsErr(rc) -/* Forward declares */ - /* Doc strings */ PyDoc_STRVAR(module_doc, "This module provides access to the Windows registry API.\n" @@ -114,7 +119,7 @@ typedef struct { HKEY hkey; } PyHKEYObject; -#define PyHKEY_Check(op) Py_IS_TYPE(op, &PyHKEY_Type) +#define PyHKEY_Check(st, op) Py_IS_TYPE(op, st->PyHKEY_Type) static char *failMsg = "bad operand type"; @@ -147,7 +152,18 @@ PyHKEY_deallocFunc(PyObject *ob) PyHKEYObject *obkey = (PyHKEYObject *)ob; if (obkey->hkey) RegCloseKey((HKEY)obkey->hkey); - PyObject_Free(ob); + + PyTypeObject *tp = Py_TYPE(ob); + PyObject_GC_UnTrack(ob); + PyObject_GC_Del(ob); + Py_DECREF(tp); +} + +static int +PyHKEY_traverseFunc(PyHKEYObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; } static int @@ -189,29 +205,6 @@ PyHKEY_hashFunc(PyObject *ob) } -static PyNumberMethods PyHKEY_NumberMethods = -{ - PyHKEY_binaryFailureFunc, /* nb_add */ - PyHKEY_binaryFailureFunc, /* nb_subtract */ - PyHKEY_binaryFailureFunc, /* nb_multiply */ - PyHKEY_binaryFailureFunc, /* nb_remainder */ - PyHKEY_binaryFailureFunc, /* nb_divmod */ - PyHKEY_ternaryFailureFunc, /* nb_power */ - PyHKEY_unaryFailureFunc, /* nb_negative */ - PyHKEY_unaryFailureFunc, /* nb_positive */ - PyHKEY_unaryFailureFunc, /* nb_absolute */ - PyHKEY_boolFunc, /* nb_bool */ - PyHKEY_unaryFailureFunc, /* nb_invert */ - PyHKEY_binaryFailureFunc, /* nb_lshift */ - PyHKEY_binaryFailureFunc, /* nb_rshift */ - PyHKEY_binaryFailureFunc, /* nb_and */ - PyHKEY_binaryFailureFunc, /* nb_xor */ - PyHKEY_binaryFailureFunc, /* nb_or */ - PyHKEY_intFunc, /* nb_int */ - 0, /* nb_reserved */ - PyHKEY_unaryFailureFunc, /* nb_float */ -}; - /*[clinic input] module winreg class winreg.HKEYType "PyHKEYObject *" "&PyHKEY_Type" @@ -229,6 +222,14 @@ class HKEY_converter(CConverter): type = 'HKEY' converter = 'clinic_HKEY_converter' + def parse_arg(self, argname, displayname): + return """ + if (!{converter}(_PyModule_GetState(module), {argname}, &{paramname})) {{{{ + goto exit; + }}}} + """.format(argname=argname, paramname=self.parser_name, + converter=self.converter) + class HKEY_return_converter(CReturnConverter): type = 'HKEY' @@ -236,7 +237,7 @@ class HKEY_return_converter(CReturnConverter): self.declare(data) self.err_occurred_if_null_pointer("_return_value", data) data.return_conversion.append( - 'return_value = PyHKEY_FromHKEY(_return_value);\n') + 'return_value = PyHKEY_FromHKEY(_PyModule_GetState(module), _return_value);\n') # HACK: this only works for PyHKEYObjects, nothing else. # Should this be generalized and enshrined in clinic.py, @@ -249,7 +250,7 @@ class self_return_converter(CReturnConverter): data.return_conversion.append( 'return_value = (PyObject *)_return_value;\n') [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=2ebb7a4922d408d6]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=17e645060c7b8ae1]*/ #include "clinic/winreg.c.h" @@ -270,8 +271,11 @@ static PyObject * winreg_HKEYType_Close_impl(PyHKEYObject *self) /*[clinic end generated code: output=fced3a624fb0c344 input=6786ac75f6b89de6]*/ { - if (!PyHKEY_Close((PyObject *)self)) + winreg_state *st = _PyType_GetModuleState(Py_TYPE(self)); + assert(st != NULL); + if (!PyHKEY_Close(st, (PyObject *)self)) { return NULL; + } Py_RETURN_NONE; } @@ -327,8 +331,11 @@ winreg_HKEYType___exit___impl(PyHKEYObject *self, PyObject *exc_type, PyObject *exc_value, PyObject *traceback) /*[clinic end generated code: output=923ebe7389e6a263 input=fb32489ee92403c7]*/ { - if (!PyHKEY_Close((PyObject *)self)) + winreg_state *st = _PyType_GetModuleState(Py_TYPE(self)); + assert(st != NULL); + if (!PyHKEY_Close(st, (PyObject *)self)) { return NULL; + } Py_RETURN_NONE; } @@ -350,62 +357,71 @@ static PyMemberDef PyHKEY_memberlist[] = { {NULL} /* Sentinel */ }; -/* The type itself */ -PyTypeObject PyHKEY_Type = -{ - PyVarObject_HEAD_INIT(0, 0) /* fill in type at module init */ - "PyHKEY", - sizeof(PyHKEYObject), - 0, - PyHKEY_deallocFunc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - &PyHKEY_NumberMethods, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - PyHKEY_hashFunc, /* tp_hash */ - 0, /* tp_call */ - PyHKEY_strFunc, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - 0, /* tp_flags */ - PyHKEY_doc, /* tp_doc */ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - PyHKEY_methods, /*tp_methods*/ - PyHKEY_memberlist, /*tp_members*/ +static PyType_Slot pyhkey_type_slots[] = { + {Py_tp_dealloc, PyHKEY_deallocFunc}, + {Py_tp_members, PyHKEY_memberlist}, + {Py_tp_methods, PyHKEY_methods}, + {Py_tp_doc, (char *)PyHKEY_doc}, + {Py_tp_traverse, PyHKEY_traverseFunc}, + {Py_tp_hash, PyHKEY_hashFunc}, + {Py_tp_str, PyHKEY_strFunc}, + + // Number protocol + {Py_nb_add, PyHKEY_binaryFailureFunc}, + {Py_nb_subtract, PyHKEY_binaryFailureFunc}, + {Py_nb_multiply, PyHKEY_binaryFailureFunc}, + {Py_nb_remainder, PyHKEY_binaryFailureFunc}, + {Py_nb_divmod, PyHKEY_binaryFailureFunc}, + {Py_nb_power, PyHKEY_ternaryFailureFunc}, + {Py_nb_negative, PyHKEY_unaryFailureFunc}, + {Py_nb_positive, PyHKEY_unaryFailureFunc}, + {Py_nb_absolute, PyHKEY_unaryFailureFunc}, + {Py_nb_bool, PyHKEY_boolFunc}, + {Py_nb_invert, PyHKEY_unaryFailureFunc}, + {Py_nb_lshift, PyHKEY_binaryFailureFunc}, + {Py_nb_rshift, PyHKEY_binaryFailureFunc}, + {Py_nb_and, PyHKEY_binaryFailureFunc}, + {Py_nb_xor, PyHKEY_binaryFailureFunc}, + {Py_nb_or, PyHKEY_binaryFailureFunc}, + {Py_nb_int, PyHKEY_intFunc}, + {Py_nb_float, PyHKEY_unaryFailureFunc}, + {0, NULL}, +}; + +static PyType_Spec pyhkey_type_spec = { + .name = "winreg.PyHKEY", + .basicsize = sizeof(PyHKEYObject), + .flags = (Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE | + Py_TPFLAGS_DISALLOW_INSTANTIATION), + .slots = pyhkey_type_slots, }; /************************************************************************ The public PyHKEY API (well, not public yet :-) ************************************************************************/ PyObject * -PyHKEY_New(HKEY hInit) +PyHKEY_New(PyObject *m, HKEY hInit) { - PyHKEYObject *key = PyObject_New(PyHKEYObject, &PyHKEY_Type); - if (key) - key->hkey = hInit; + winreg_state *st = _PyModule_GetState(m); + PyHKEYObject *key = PyObject_GC_New(PyHKEYObject, st->PyHKEY_Type); + if (key == NULL) { + return NULL; + } + key->hkey = hInit; + PyObject_GC_Track(key); return (PyObject *)key; } BOOL -PyHKEY_Close(PyObject *ob_handle) +PyHKEY_Close(winreg_state *st, PyObject *ob_handle) { LONG rc; HKEY key; - if (!PyHKEY_AsHKEY(ob_handle, &key, TRUE)) { + if (!PyHKEY_AsHKEY(st, ob_handle, &key, TRUE)) { return FALSE; } - if (PyHKEY_Check(ob_handle)) { + if (PyHKEY_Check(st, ob_handle)) { ((PyHKEYObject*)ob_handle)->hkey = 0; } rc = key ? RegCloseKey(key) : ERROR_SUCCESS; @@ -415,7 +431,7 @@ PyHKEY_Close(PyObject *ob_handle) } BOOL -PyHKEY_AsHKEY(PyObject *ob, HKEY *pHANDLE, BOOL bNoneOK) +PyHKEY_AsHKEY(winreg_state *st, PyObject *ob, HKEY *pHANDLE, BOOL bNoneOK) { if (ob == Py_None) { if (!bNoneOK) { @@ -426,7 +442,7 @@ PyHKEY_AsHKEY(PyObject *ob, HKEY *pHANDLE, BOOL bNoneOK) } *pHANDLE = (HKEY)0; } - else if (PyHKEY_Check(ob)) { + else if (PyHKEY_Check(st ,ob)) { PyHKEYObject *pH = (PyHKEYObject *)ob; *pHANDLE = pH->hkey; } @@ -447,23 +463,24 @@ PyHKEY_AsHKEY(PyObject *ob, HKEY *pHANDLE, BOOL bNoneOK) } BOOL -clinic_HKEY_converter(PyObject *ob, void *p) +clinic_HKEY_converter(winreg_state *st, PyObject *ob, void *p) { - if (!PyHKEY_AsHKEY(ob, (HKEY *)p, FALSE)) + if (!PyHKEY_AsHKEY(st, ob, (HKEY *)p, FALSE)) { return FALSE; + } return TRUE; } PyObject * -PyHKEY_FromHKEY(HKEY h) +PyHKEY_FromHKEY(winreg_state *st, HKEY h) { - /* Inline PyObject_New */ - PyHKEYObject *op = (PyHKEYObject *) PyObject_Malloc(sizeof(PyHKEYObject)); + PyHKEYObject *op = (PyHKEYObject *)PyObject_GC_New(PyHKEYObject, + st->PyHKEY_Type); if (op == NULL) { - return PyErr_NoMemory(); + return NULL; } - _PyObject_Init((PyObject*)op, &PyHKEY_Type); op->hkey = h; + PyObject_GC_Track(op); return (PyObject *)op; } @@ -472,11 +489,11 @@ PyHKEY_FromHKEY(HKEY h) The module methods ************************************************************************/ BOOL -PyWinObject_CloseHKEY(PyObject *obHandle) +PyWinObject_CloseHKEY(winreg_state *st, PyObject *obHandle) { BOOL ok; - if (PyHKEY_Check(obHandle)) { - ok = PyHKEY_Close(obHandle); + if (PyHKEY_Check(st, obHandle)) { + ok = PyHKEY_Close(st, obHandle); } #if SIZEOF_LONG >= SIZEOF_HKEY else if (PyLong_Check(obHandle)) { @@ -826,8 +843,9 @@ static PyObject * winreg_CloseKey(PyObject *module, PyObject *hkey) /*[clinic end generated code: output=a4fa537019a80d15 input=5b1aac65ba5127ad]*/ { - if (!PyHKEY_Close(hkey)) + if (!PyHKEY_Close(_PyModule_GetState(module), hkey)) { return NULL; + } Py_RETURN_NONE; } @@ -2061,7 +2079,7 @@ static struct PyMethodDef winreg_methods[] = { #define ADD_INT(VAL) do { \ if (PyModule_AddIntConstant(m, #VAL, VAL) < 0) { \ - goto error; \ + return -1; \ } \ } while (0) @@ -2079,38 +2097,25 @@ inskey(PyObject *mod, char *name, HKEY key) #define ADD_KEY(VAL) do { \ if (inskey(m, #VAL, VAL) < 0) { \ - goto error; \ + return -1; \ } \ } while (0) - -static struct PyModuleDef winregmodule = { - PyModuleDef_HEAD_INIT, - "winreg", - module_doc, - -1, - winreg_methods, - NULL, - NULL, - NULL, - NULL -}; - -PyMODINIT_FUNC PyInit_winreg(void) +static int +exec_module(PyObject *m) { - PyObject *m = PyModule_Create(&winregmodule); - if (m == NULL) { - return NULL; - } - PyHKEY_Type.tp_doc = PyHKEY_doc; - if (PyType_Ready(&PyHKEY_Type) < 0) { - goto error; + winreg_state *st = (winreg_state *)_PyModule_GetState(m); + + st->PyHKEY_Type = (PyTypeObject *) + PyType_FromModuleAndSpec(m, &pyhkey_type_spec, NULL); + if (st->PyHKEY_Type == NULL) { + return -1; } - if (PyModule_AddObjectRef(m, "HKEYType", (PyObject *)&PyHKEY_Type) < 0) { - goto error; + if (PyModule_AddObjectRef(m, "HKEYType", (PyObject *)st->PyHKEY_Type) < 0) { + return -1; } if (PyModule_AddObjectRef(m, "error", PyExc_OSError) < 0) { - goto error; + return -1; } /* Add the relevant constants */ @@ -2174,12 +2179,44 @@ PyMODINIT_FUNC PyInit_winreg(void) ADD_INT(REG_RESOURCE_REQUIREMENTS_LIST); #undef ADD_INT + return 0; +} - return m; +static PyModuleDef_Slot winreg_slots[] = { + {Py_mod_exec, exec_module}, + {0, NULL} +}; -error: - Py_DECREF(m); - return NULL; +static int +winreg_traverse(PyObject *module, visitproc visit, void *arg) +{ + winreg_state *state = _PyModule_GetState(module); + Py_VISIT(state->PyHKEY_Type); + return 0; +} + +static int +winreg_clear(PyObject *module) +{ + winreg_state *state = _PyModule_GetState(module); + Py_CLEAR(state->PyHKEY_Type); + return 0; +} + +static struct PyModuleDef winregmodule = { + .m_base = PyModuleDef_HEAD_INIT, + .m_name = "winreg", + .m_doc = module_doc, + .m_size = sizeof(winreg_state), + .m_methods = winreg_methods, + .m_slots = winreg_slots, + .m_traverse = winreg_traverse, + .m_clear = winreg_clear, +}; + +PyMODINIT_FUNC PyInit_winreg(void) +{ + return PyModuleDef_Init(&winregmodule); } #endif /* MS_WINDOWS_DESKTOP || MS_WINDOWS_SYSTEM || MS_WINDOWS_GAMES */ From webhook-mailer at python.org Mon Apr 17 19:33:36 2023 From: webhook-mailer at python.org (carljm) Date: Mon, 17 Apr 2023 23:33:36 -0000 Subject: [Python-checkins] gh-103449: Fix a bug in dataclass docstring generation (#103454) Message-ID: https://github.com/python/cpython/commit/b57f55c23e15654e9dd77680ff1462603e360b76 commit: b57f55c23e15654e9dd77680ff1462603e360b76 branch: main author: Nikita Sobolev committer: carljm date: 2023-04-17T17:33:22-06:00 summary: gh-103449: Fix a bug in dataclass docstring generation (#103454) files: A Misc/NEWS.d/next/Library/2023-04-11-21-38-39.gh-issue-103449.-nxmhb.rst M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 4026c8b77975..a73cdc22a5f4 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1128,8 +1128,13 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen, if not getattr(cls, '__doc__'): # Create a class doc-string. - cls.__doc__ = (cls.__name__ + - str(inspect.signature(cls)).replace(' -> None', '')) + try: + # In some cases fetching a signature is not possible. + # But, we surely should not fail in this case. + text_sig = str(inspect.signature(cls)).replace(' -> None', '') + except (TypeError, ValueError): + text_sig = '' + cls.__doc__ = (cls.__name__ + text_sig) if match_args: # I could probably compute this once diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 6888680105c4..ae8bfcc149e8 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -2297,6 +2297,19 @@ class C: self.assertDocStrEqual(C.__doc__, "C(x:collections.deque=)") + def test_docstring_with_no_signature(self): + # See https://github.com/python/cpython/issues/103449 + class Meta(type): + __call__ = dict + class Base(metaclass=Meta): + pass + + @dataclass + class C(Base): + pass + + self.assertDocStrEqual(C.__doc__, "C") + class TestInit(unittest.TestCase): def test_base_has_init(self): diff --git a/Misc/NEWS.d/next/Library/2023-04-11-21-38-39.gh-issue-103449.-nxmhb.rst b/Misc/NEWS.d/next/Library/2023-04-11-21-38-39.gh-issue-103449.-nxmhb.rst new file mode 100644 index 000000000000..0b2b47af1cba --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-11-21-38-39.gh-issue-103449.-nxmhb.rst @@ -0,0 +1 @@ +Fix a bug in doc string generation in :func:`dataclasses.dataclass`. From webhook-mailer at python.org Mon Apr 17 21:21:45 2023 From: webhook-mailer at python.org (merwok) Date: Tue, 18 Apr 2023 01:21:45 -0000 Subject: [Python-checkins] gh-67230: update whatsnew note for csv changes (#103598) Message-ID: https://github.com/python/cpython/commit/e35e0f15eba64a1dcbab10bbbd2ce276e190dcfa commit: e35e0f15eba64a1dcbab10bbbd2ce276e190dcfa branch: main author: Skip Montanaro committer: merwok date: 2023-04-17T21:21:19-04:00 summary: gh-67230: update whatsnew note for csv changes (#103598) files: M Doc/whatsnew/3.12.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 4165b16ba764..2a371ebf55a1 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -258,7 +258,7 @@ csv * Add :data:`~csv.QUOTE_NOTNULL` and :data:`~csv.QUOTE_STRINGS` flags to provide finer grained control of ``None`` and empty strings by - :class:`~csv.reader` and :class:`~csv.writer` objects. + :class:`~csv.writer` objects. inspect ------- From webhook-mailer at python.org Mon Apr 17 22:57:59 2023 From: webhook-mailer at python.org (hugovk) Date: Tue, 18 Apr 2023 02:57:59 -0000 Subject: [Python-checkins] GH-103484: Docs: add linkcheck allowed redirects entries for most cases (#103569) Message-ID: https://github.com/python/cpython/commit/f39e00f9521a0d412a5fc9a50f2a553ec2bb1a7c commit: f39e00f9521a0d412a5fc9a50f2a553ec2bb1a7c branch: main author: Rafael Fontenelle committer: hugovk date: 2023-04-18T05:57:53+03:00 summary: GH-103484: Docs: add linkcheck allowed redirects entries for most cases (#103569) Co-authored-by: Hugo van Kemenade files: M Doc/conf.py diff --git a/Doc/conf.py b/Doc/conf.py index e99b801d0ae8..60404fd3829e 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -254,9 +254,14 @@ # Options for the link checker # ---------------------------- -# Ignore certain URLs. -linkcheck_ignore = [r'https://bugs.python.org/(issue)?\d+'] - +linkcheck_allowed_redirects = { + # bpo-NNNN -> BPO -> GH Issues + r'https://bugs.python.org/issue\?@action=redirect&bpo=\d+': 'https://github.com/python/cpython/issues/\d+', + # GH-NNNN used to refer to pull requests + r'https://github.com/python/cpython/issues/\d+': 'https://github.com/python/cpython/pull/\d+', + # :source:`something` linking files in the repository + r'https://github.com/python/cpython/tree/.*': 'https://github.com/python/cpython/blob/.*' +} # Options for extensions # ---------------------- From webhook-mailer at python.org Mon Apr 17 23:06:59 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 18 Apr 2023 03:06:59 -0000 Subject: [Python-checkins] GH-103484: Docs: add linkcheck allowed redirects entries for most cases (GH-103569) Message-ID: https://github.com/python/cpython/commit/1dad3d10714fe9611769196fde4e94bb63eb7f17 commit: 1dad3d10714fe9611769196fde4e94bb63eb7f17 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-17T20:06:52-07:00 summary: GH-103484: Docs: add linkcheck allowed redirects entries for most cases (GH-103569) (cherry picked from commit f39e00f9521a0d412a5fc9a50f2a553ec2bb1a7c) Co-authored-by: Rafael Fontenelle Co-authored-by: Hugo van Kemenade files: M Doc/conf.py diff --git a/Doc/conf.py b/Doc/conf.py index 18aff5d58ce8..d89470973dac 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -242,9 +242,14 @@ # Options for the link checker # ---------------------------- -# Ignore certain URLs. -linkcheck_ignore = [r'https://bugs.python.org/(issue)?\d+'] - +linkcheck_allowed_redirects = { + # bpo-NNNN -> BPO -> GH Issues + r'https://bugs.python.org/issue\?@action=redirect&bpo=\d+': 'https://github.com/python/cpython/issues/\d+', + # GH-NNNN used to refer to pull requests + r'https://github.com/python/cpython/issues/\d+': 'https://github.com/python/cpython/pull/\d+', + # :source:`something` linking files in the repository + r'https://github.com/python/cpython/tree/.*': 'https://github.com/python/cpython/blob/.*' +} # Options for extensions # ---------------------- From webhook-mailer at python.org Tue Apr 18 00:43:48 2023 From: webhook-mailer at python.org (pradyunsg) Date: Tue, 18 Apr 2023 04:43:48 -0000 Subject: [Python-checkins] gh-95299: Stop installing setuptools as a part of ensurepip and venv (#101039) Message-ID: https://github.com/python/cpython/commit/ece20dba120a1a4745721c49f8d7389d4b1ee2a7 commit: ece20dba120a1a4745721c49f8d7389d4b1ee2a7 branch: main author: Pradyun Gedam committer: pradyunsg date: 2023-04-17T23:43:34-05:00 summary: gh-95299: Stop installing setuptools as a part of ensurepip and venv (#101039) Remove the bundled setuptools wheel from ensurepip, and stop installing setuptools in environments created by venv. Co-Authored-by: Hugo van Kemenade Co-authored-by: C.A.M. Gerlach Co-authored-by: Oleg Iarygin files: A Misc/NEWS.d/next/Library/2023-01-14-17-54-56.gh-issue-95299.vUhpKz.rst D Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl M .github/workflows/verify-ensurepip-wheels.yml M Doc/library/venv.rst M Doc/using/venv-create.inc M Doc/whatsnew/3.12.rst M Lib/ensurepip/__init__.py M Lib/test/test_ensurepip.py M Lib/test/test_venv.py M Lib/venv/__init__.py M Mac/BuildScript/scripts/postflight.ensurepip M Mac/Makefile.in M Tools/build/verify_ensurepip_wheels.py diff --git a/.github/workflows/verify-ensurepip-wheels.yml b/.github/workflows/verify-ensurepip-wheels.yml index d4a2cb6846c1..17d841f1f1c5 100644 --- a/.github/workflows/verify-ensurepip-wheels.yml +++ b/.github/workflows/verify-ensurepip-wheels.yml @@ -1,4 +1,4 @@ -name: Verify bundled pip and setuptools +name: Verify bundled wheels on: workflow_dispatch: @@ -29,5 +29,5 @@ jobs: - uses: actions/setup-python at v4 with: python-version: '3' - - name: Compare checksums of bundled pip and setuptools to ones published on PyPI + - name: Compare checksum of bundled wheels to the ones published on PyPI run: ./Tools/build/verify_ensurepip_wheels.py diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index 240ab139838d..52bf99e5bb0f 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -284,11 +284,14 @@ creation according to their needs, the :class:`EnvBuilder` class. .. method:: upgrade_dependencies(context) - Upgrades the core venv dependency packages (currently ``pip`` and - ``setuptools``) in the environment. This is done by shelling out to the + Upgrades the core venv dependency packages (currently ``pip``) + in the environment. This is done by shelling out to the ``pip`` executable in the environment. .. versionadded:: 3.9 + .. versionchanged:: 3.12 + + ``setuptools`` is no longer a core venv dependency. .. method:: post_setup(context) diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc index 43ee6b7807d5..2fc901264822 100644 --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -61,12 +61,16 @@ The command, if run with ``-h``, will show the available options:: environment (pip is bootstrapped by default) --prompt PROMPT Provides an alternative prompt prefix for this environment. - --upgrade-deps Upgrade core dependencies: pip setuptools to the + --upgrade-deps Upgrade core dependencies (pip) to the latest version in PyPI Once an environment has been created, you may wish to activate it, e.g. by sourcing an activate script in its bin directory. +.. versionchanged:: 3.12 + + ``setuptools`` is no longer a core venv dependency. + .. versionchanged:: 3.9 Add ``--upgrade-deps`` option to upgrade pip + setuptools to the latest on PyPI @@ -104,4 +108,3 @@ invoked to bootstrap ``pip`` into the virtual environment. Multiple paths can be given to ``venv``, in which case an identical virtual environment will be created, according to the given options, at each provided path. - diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 2a371ebf55a1..bd95bfeea80c 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -731,6 +731,24 @@ Removed project can be installed: it still provides ``distutils``. (Contributed by Victor Stinner in :gh:`92584`.) +* Remove the bundled setuptools wheel from :mod:`ensurepip`, + and stop installing setuptools in environments created by :mod:`venv`. + + ``pip (>= 22.1)`` does not require setuptools to be installed in the + environment. ``setuptools``-based (and ``distutils``-based) packages + can still be used with ``pip install``, since pip will provide + ``setuptools`` in the build environment it uses for building a + package. + + ``easy_install``, ``pkg_resources``, ``setuptools`` and ``distutils`` + are no longer provided by default in environments created with + ``venv`` or bootstrapped with ``ensurepip``, since they are part of + the ``setuptools`` package. For projects relying on these at runtime, + the ``setuptools`` project should be declared as a dependency and + installed separately (typically, using pip). + + (Contributed by Pradyun Gedam in :gh:`95299`.) + * Removed many old deprecated :mod:`unittest` features: - A number of :class:`~unittest.TestCase` method aliases: diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 00e77749e25e..69b23de9e050 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -9,11 +9,9 @@ __all__ = ["version", "bootstrap"] -_PACKAGE_NAMES = ('setuptools', 'pip') -_SETUPTOOLS_VERSION = "65.5.0" +_PACKAGE_NAMES = ('pip',) _PIP_VERSION = "23.0.1" _PROJECTS = [ - ("setuptools", _SETUPTOOLS_VERSION, "py3"), ("pip", _PIP_VERSION, "py3"), ] @@ -153,17 +151,17 @@ def _bootstrap(*, root=None, upgrade=False, user=False, _disable_pip_configuration_settings() - # By default, installing pip and setuptools installs all of the + # By default, installing pip installs all of the # following scripts (X.Y == running Python version): # - # pip, pipX, pipX.Y, easy_install, easy_install-X.Y + # pip, pipX, pipX.Y # # pip 1.5+ allows ensurepip to request that some of those be left out if altinstall: - # omit pip, pipX and easy_install + # omit pip, pipX os.environ["ENSUREPIP_OPTIONS"] = "altinstall" elif not default_pip: - # omit pip and easy_install + # omit pip os.environ["ENSUREPIP_OPTIONS"] = "install" with tempfile.TemporaryDirectory() as tmpdir: @@ -271,14 +269,14 @@ def _main(argv=None): action="store_true", default=False, help=("Make an alternate install, installing only the X.Y versioned " - "scripts (Default: pipX, pipX.Y, easy_install-X.Y)."), + "scripts (Default: pipX, pipX.Y)."), ) parser.add_argument( "--default-pip", action="store_true", default=False, help=("Make a default pip install, installing the unqualified pip " - "and easy_install in addition to the versioned scripts."), + "in addition to the versioned scripts."), ) args = parser.parse_args(argv) diff --git a/Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl deleted file mode 100644 index 123a13e2c6b2..000000000000 Binary files a/Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl and /dev/null differ diff --git a/Lib/test/test_ensurepip.py b/Lib/test/test_ensurepip.py index bfca0cd7fbe4..69ab2a4feaa9 100644 --- a/Lib/test/test_ensurepip.py +++ b/Lib/test/test_ensurepip.py @@ -20,7 +20,6 @@ def test_version(self): # Test version() with tempfile.TemporaryDirectory() as tmpdir: self.touch(tmpdir, "pip-1.2.3b1-py2.py3-none-any.whl") - self.touch(tmpdir, "setuptools-49.1.3-py3-none-any.whl") with (unittest.mock.patch.object(ensurepip, '_PACKAGES', None), unittest.mock.patch.object(ensurepip, '_WHEEL_PKG_DIR', tmpdir)): self.assertEqual(ensurepip.version(), '1.2.3b1') @@ -36,15 +35,12 @@ def test_get_packages_no_dir(self): # use bundled wheel packages self.assertIsNotNone(packages['pip'].wheel_name) - self.assertIsNotNone(packages['setuptools'].wheel_name) def test_get_packages_with_dir(self): # Test _get_packages() with a wheel package directory - setuptools_filename = "setuptools-49.1.3-py3-none-any.whl" pip_filename = "pip-20.2.2-py2.py3-none-any.whl" with tempfile.TemporaryDirectory() as tmpdir: - self.touch(tmpdir, setuptools_filename) self.touch(tmpdir, pip_filename) # not used, make sure that it's ignored self.touch(tmpdir, "wheel-0.34.2-py2.py3-none-any.whl") @@ -53,15 +49,12 @@ def test_get_packages_with_dir(self): unittest.mock.patch.object(ensurepip, '_WHEEL_PKG_DIR', tmpdir)): packages = ensurepip._get_packages() - self.assertEqual(packages['setuptools'].version, '49.1.3') - self.assertEqual(packages['setuptools'].wheel_path, - os.path.join(tmpdir, setuptools_filename)) self.assertEqual(packages['pip'].version, '20.2.2') self.assertEqual(packages['pip'].wheel_path, os.path.join(tmpdir, pip_filename)) # wheel package is ignored - self.assertEqual(sorted(packages), ['pip', 'setuptools']) + self.assertEqual(sorted(packages), ['pip']) class EnsurepipMixin: @@ -92,13 +85,13 @@ def test_basic_bootstrapping(self): self.run_pip.assert_called_once_with( [ "install", "--no-cache-dir", "--no-index", "--find-links", - unittest.mock.ANY, "setuptools", "pip", + unittest.mock.ANY, "pip", ], unittest.mock.ANY, ) additional_paths = self.run_pip.call_args[0][1] - self.assertEqual(len(additional_paths), 2) + self.assertEqual(len(additional_paths), 1) def test_bootstrapping_with_root(self): ensurepip.bootstrap(root="/foo/bar/") @@ -107,7 +100,7 @@ def test_bootstrapping_with_root(self): [ "install", "--no-cache-dir", "--no-index", "--find-links", unittest.mock.ANY, "--root", "/foo/bar/", - "setuptools", "pip", + "pip", ], unittest.mock.ANY, ) @@ -118,7 +111,7 @@ def test_bootstrapping_with_user(self): self.run_pip.assert_called_once_with( [ "install", "--no-cache-dir", "--no-index", "--find-links", - unittest.mock.ANY, "--user", "setuptools", "pip", + unittest.mock.ANY, "--user", "pip", ], unittest.mock.ANY, ) @@ -129,7 +122,7 @@ def test_bootstrapping_with_upgrade(self): self.run_pip.assert_called_once_with( [ "install", "--no-cache-dir", "--no-index", "--find-links", - unittest.mock.ANY, "--upgrade", "setuptools", "pip", + unittest.mock.ANY, "--upgrade", "pip", ], unittest.mock.ANY, ) @@ -140,7 +133,7 @@ def test_bootstrapping_with_verbosity_1(self): self.run_pip.assert_called_once_with( [ "install", "--no-cache-dir", "--no-index", "--find-links", - unittest.mock.ANY, "-v", "setuptools", "pip", + unittest.mock.ANY, "-v", "pip", ], unittest.mock.ANY, ) @@ -151,7 +144,7 @@ def test_bootstrapping_with_verbosity_2(self): self.run_pip.assert_called_once_with( [ "install", "--no-cache-dir", "--no-index", "--find-links", - unittest.mock.ANY, "-vv", "setuptools", "pip", + unittest.mock.ANY, "-vv", "pip", ], unittest.mock.ANY, ) @@ -162,7 +155,7 @@ def test_bootstrapping_with_verbosity_3(self): self.run_pip.assert_called_once_with( [ "install", "--no-cache-dir", "--no-index", "--find-links", - unittest.mock.ANY, "-vvv", "setuptools", "pip", + unittest.mock.ANY, "-vvv", "pip", ], unittest.mock.ANY, ) @@ -239,7 +232,6 @@ def test_uninstall(self): self.run_pip.assert_called_once_with( [ "uninstall", "-y", "--disable-pip-version-check", "pip", - "setuptools", ] ) @@ -250,7 +242,6 @@ def test_uninstall_with_verbosity_1(self): self.run_pip.assert_called_once_with( [ "uninstall", "-y", "--disable-pip-version-check", "-v", "pip", - "setuptools", ] ) @@ -261,7 +252,6 @@ def test_uninstall_with_verbosity_2(self): self.run_pip.assert_called_once_with( [ "uninstall", "-y", "--disable-pip-version-check", "-vv", "pip", - "setuptools", ] ) @@ -272,7 +262,7 @@ def test_uninstall_with_verbosity_3(self): self.run_pip.assert_called_once_with( [ "uninstall", "-y", "--disable-pip-version-check", "-vvv", - "pip", "setuptools", + "pip" ] ) @@ -312,13 +302,13 @@ def test_basic_bootstrapping(self): self.run_pip.assert_called_once_with( [ "install", "--no-cache-dir", "--no-index", "--find-links", - unittest.mock.ANY, "setuptools", "pip", + unittest.mock.ANY, "pip", ], unittest.mock.ANY, ) additional_paths = self.run_pip.call_args[0][1] - self.assertEqual(len(additional_paths), 2) + self.assertEqual(len(additional_paths), 1) self.assertEqual(exit_code, 0) def test_bootstrapping_error_code(self): @@ -344,7 +334,6 @@ def test_basic_uninstall(self): self.run_pip.assert_called_once_with( [ "uninstall", "-y", "--disable-pip-version-check", "pip", - "setuptools", ] ) diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index 7cccbe84f4eb..333b97688af5 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -227,7 +227,6 @@ def pip_cmd_checker(cmd, **kwargs): 'install', '--upgrade', 'pip', - 'setuptools' ] ) @@ -745,7 +744,6 @@ def do_test_with_pip(self, system_site_packages): # future pip versions, this test can likely be relaxed further. out = out.decode("latin-1") # Force to text, prevent decoding errors self.assertIn("Successfully uninstalled pip", out) - self.assertIn("Successfully uninstalled setuptools", out) # Check pip is now gone from the virtual environment. This only # applies in the system_site_packages=False case, because in the # other case, pip may still be available in the system site-packages diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py index 2f87c62ccba8..2173c9b13e5c 100644 --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -13,7 +13,7 @@ import types -CORE_VENV_DEPS = ('pip', 'setuptools') +CORE_VENV_DEPS = ('pip',) logger = logging.getLogger(__name__) @@ -523,7 +523,7 @@ def main(args=None): 'this environment.') parser.add_argument('--upgrade-deps', default=False, action='store_true', dest='upgrade_deps', - help=f'Upgrade core dependencies: {", ".join(CORE_VENV_DEPS)} ' + help=f'Upgrade core dependencies ({", ".join(CORE_VENV_DEPS)}) ' 'to the latest version in PyPI') options = parser.parse_args(args) if options.upgrade and options.clear: diff --git a/Mac/BuildScript/scripts/postflight.ensurepip b/Mac/BuildScript/scripts/postflight.ensurepip index 36d05945b6fd..ce3c6c1c2bf9 100755 --- a/Mac/BuildScript/scripts/postflight.ensurepip +++ b/Mac/BuildScript/scripts/postflight.ensurepip @@ -56,19 +56,19 @@ if [ -d /usr/local/bin ] ; then cd /usr/local/bin - # Create pipx.y and easy_install-x.y links if /usr/local/bin/pythonx.y + # Create pipx.y links if /usr/local/bin/pythonx.y # is linked to this framework version install_links_if_our_fw "python${PYVER}" \ - "pip${PYVER}" "easy_install-${PYVER}" + "pip${PYVER}" # Create pipx link if /usr/local/bin/pythonx is linked to this version install_links_if_our_fw "python${PYMAJOR}" \ "pip${PYMAJOR}" - # Create pip and easy_install link if /usr/local/bin/python + # Create pip link if /usr/local/bin/python # is linked to this version install_links_if_our_fw "python" \ - "pip" "easy_install" + "pip" ) fi exit 0 diff --git a/Mac/Makefile.in b/Mac/Makefile.in index f96912884145..69ab41989885 100644 --- a/Mac/Makefile.in +++ b/Mac/Makefile.in @@ -166,7 +166,6 @@ altinstallunixtools: -if test "x$(ENSUREPIP)" != "xno" ; then \ cd "$(DESTDIR)$(FRAMEWORKUNIXTOOLSPREFIX)/bin" && \ for fn in \ - easy_install-$(VERSION) \ pip$(VERSION) \ ; \ do \ diff --git a/Misc/NEWS.d/next/Library/2023-01-14-17-54-56.gh-issue-95299.vUhpKz.rst b/Misc/NEWS.d/next/Library/2023-01-14-17-54-56.gh-issue-95299.vUhpKz.rst new file mode 100644 index 000000000000..29c30848e09a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-01-14-17-54-56.gh-issue-95299.vUhpKz.rst @@ -0,0 +1 @@ +Remove the bundled setuptools wheel from ``ensurepip``, and stop installing setuptools in environments created by ``venv``. diff --git a/Tools/build/verify_ensurepip_wheels.py b/Tools/build/verify_ensurepip_wheels.py index 044d1fd6b3cf..09fd5d9e3103 100755 --- a/Tools/build/verify_ensurepip_wheels.py +++ b/Tools/build/verify_ensurepip_wheels.py @@ -14,7 +14,7 @@ from pathlib import Path from urllib.request import urlopen -PACKAGE_NAMES = ("pip", "setuptools") +PACKAGE_NAMES = ("pip",) ENSURE_PIP_ROOT = Path(__file__).parent.parent.parent / "Lib/ensurepip" WHEEL_DIR = ENSURE_PIP_ROOT / "_bundled" ENSURE_PIP_INIT_PY_TEXT = (ENSURE_PIP_ROOT / "__init__.py").read_text(encoding="utf-8") From webhook-mailer at python.org Tue Apr 18 07:19:06 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Tue, 18 Apr 2023 11:19:06 -0000 Subject: [Python-checkins] gh-101100: Fix broken reference `__format__` in `string.rst` (#103531) Message-ID: https://github.com/python/cpython/commit/c3d015ce62f791e703bfcabb0907cfeefac768a9 commit: c3d015ce62f791e703bfcabb0907cfeefac768a9 branch: main author: yuki committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-04-18T16:48:53+05:30 summary: gh-101100: Fix broken reference `__format__` in `string.rst` (#103531) files: M Doc/library/string.rst diff --git a/Doc/library/string.rst b/Doc/library/string.rst index f55074cc5827..26b3f5000634 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -254,10 +254,10 @@ Some simple format string examples:: "Units destroyed: {players[0]}" # First element of keyword argument 'players'. The *conversion* field causes a type coercion before formatting. Normally, the -job of formatting a value is done by the :meth:`__format__` method of the value +job of formatting a value is done by the :meth:`~object.__format__` method of the value itself. However, in some cases it is desirable to force a type to be formatted as a string, overriding its own definition of formatting. By converting the -value to a string before calling :meth:`__format__`, the normal formatting logic +value to a string before calling :meth:`~object.__format__`, the normal formatting logic is bypassed. Three conversion flags are currently supported: ``'!s'`` which calls :func:`str` From webhook-mailer at python.org Tue Apr 18 07:21:34 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Tue, 18 Apr 2023 11:21:34 -0000 Subject: [Python-checkins] [Doc] Fix a typo in optparse.rst (#103504) Message-ID: https://github.com/python/cpython/commit/4e04393b2f64f9e44aefa436cbdac42db98d4ef0 commit: 4e04393b2f64f9e44aefa436cbdac42db98d4ef0 branch: main author: zyckk4 <100814967+zyckk4 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-04-18T16:51:26+05:30 summary: [Doc] Fix a typo in optparse.rst (#103504) files: M Doc/library/optparse.rst diff --git a/Doc/library/optparse.rst b/Doc/library/optparse.rst index 3e29fed0175e..468c3efbe011 100644 --- a/Doc/library/optparse.rst +++ b/Doc/library/optparse.rst @@ -2027,7 +2027,7 @@ Features of note: values.ensure_value(attr, value) If the ``attr`` attribute of ``values`` doesn't exist or is ``None``, then - ensure_value() first sets it to ``value``, and then returns 'value. This is + ensure_value() first sets it to ``value``, and then returns ``value``. This is very handy for actions like ``"extend"``, ``"append"``, and ``"count"``, all of which accumulate data in a variable and expect that variable to be of a certain type (a list for the first two, an integer for the latter). Using From webhook-mailer at python.org Tue Apr 18 12:47:34 2023 From: webhook-mailer at python.org (zooba) Date: Tue, 18 Apr 2023 16:47:34 -0000 Subject: [Python-checkins] gh-95299: Remove lingering setuptools reference in installer scripts (GH-103613) Message-ID: https://github.com/python/cpython/commit/78cac520c34b133ba32665e601adbc794282f4b7 commit: 78cac520c34b133ba32665e601adbc794282f4b7 branch: main author: Steve Dower committer: zooba date: 2023-04-18T17:47:08+01:00 summary: gh-95299: Remove lingering setuptools reference in installer scripts (GH-103613) files: M PC/layout/support/pip.py diff --git a/PC/layout/support/pip.py b/PC/layout/support/pip.py index c54acb250a25..0a6582acf348 100644 --- a/PC/layout/support/pip.py +++ b/PC/layout/support/pip.py @@ -67,7 +67,6 @@ def extract_pip_files(ns): "--no-color", "install", "pip", - "setuptools", "--upgrade", "--target", str(dest), From webhook-mailer at python.org Tue Apr 18 13:41:30 2023 From: webhook-mailer at python.org (brandtbucher) Date: Tue, 18 Apr 2023 17:41:30 -0000 Subject: [Python-checkins] GH-100530: Change the error message for non-class class patterns (GH-103576) Message-ID: https://github.com/python/cpython/commit/07804ce24c3103ee1bb141af31b9a1a0f92f5e43 commit: 07804ce24c3103ee1bb141af31b9a1a0f92f5e43 branch: main author: Nikita Sobolev committer: brandtbucher date: 2023-04-18T10:41:14-07:00 summary: GH-100530: Change the error message for non-class class patterns (GH-103576) files: A Misc/NEWS.d/next/Core and Builtins/2023-04-16-14-38-39.gh-issue-100530.OR6-sn.rst M Python/ceval.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-16-14-38-39.gh-issue-100530.OR6-sn.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-16-14-38-39.gh-issue-100530.OR6-sn.rst new file mode 100644 index 000000000000..5b1bcc4a680f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-16-14-38-39.gh-issue-100530.OR6-sn.rst @@ -0,0 +1 @@ +Clarify the error message raised when the called part of a class pattern isn't actually a class. diff --git a/Python/ceval.c b/Python/ceval.c index 8c43e3d89c2c..d8495da81e94 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -416,7 +416,7 @@ match_class(PyThreadState *tstate, PyObject *subject, PyObject *type, Py_ssize_t nargs, PyObject *kwargs) { if (!PyType_Check(type)) { - const char *e = "called match pattern must be a type"; + const char *e = "called match pattern must be a class"; _PyErr_Format(tstate, PyExc_TypeError, e); return NULL; } From webhook-mailer at python.org Tue Apr 18 19:19:31 2023 From: webhook-mailer at python.org (ethanfurman) Date: Tue, 18 Apr 2023 23:19:31 -0000 Subject: [Python-checkins] gh-103596: [Enum] do not shadow mixed-in methods/attributes (GH-103600) Message-ID: https://github.com/python/cpython/commit/700ec657c80e78fb299963ffaa684c859ddb8f87 commit: 700ec657c80e78fb299963ffaa684c859ddb8f87 branch: main author: Ethan Furman committer: ethanfurman date: 2023-04-18T16:19:23-07:00 summary: gh-103596: [Enum] do not shadow mixed-in methods/attributes (GH-103600) For example: class Book(StrEnum): title = auto() author = auto() desc = auto() Book.author.desc is Book.desc but Book.author.title() == 'Author' is commonly expected. Using upper-case member names avoids this confusion and possible performance impacts. Co-authored-by: samypr100 <3933065+samypr100 at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2023-04-17-14-47-28.gh-issue-103596.ME1y3_.rst M Doc/howto/enum.rst M Doc/library/enum.rst M Lib/enum.py M Lib/test/test_enum.py diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst index 56391a026cf8..68b75c529e92 100644 --- a/Doc/howto/enum.rst +++ b/Doc/howto/enum.rst @@ -36,8 +36,10 @@ inherits from :class:`Enum` itself. .. note:: Case of Enum Members - Because Enums are used to represent constants we recommend using - UPPER_CASE names for members, and will be using that style in our examples. + Because Enums are used to represent constants, and to help avoid issues + with name clashes between mixin-class methods/attributes and enum names, + we strongly recommend using UPPER_CASE names for members, and will be using + that style in our examples. Depending on the nature of the enum a member's value may or may not be important, but either way that value can be used to get the corresponding @@ -490,6 +492,10 @@ the :meth:`~Enum.__repr__` omits the inherited class' name. For example:: Use the :func:`!dataclass` argument ``repr=False`` to use the standard :func:`repr`. +.. versionchanged:: 3.12 + Only the dataclass fields are shown in the value area, not the dataclass' + name. + Pickling -------- @@ -992,7 +998,9 @@ but remain normal attributes. Enum members are instances of their enum class, and are normally accessed as ``EnumClass.member``. In certain situations, such as writing custom enum behavior, being able to access one member directly from another is useful, -and is supported. +and is supported; however, in order to avoid name clashes between member names +and attributes/methods from mixed-in classes, upper-case names are strongly +recommended. .. versionchanged:: 3.5 diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index 07acf9da33e2..582e06261afd 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -119,7 +119,8 @@ Module Contents :func:`~enum.property` Allows :class:`Enum` members to have attributes without conflicting with - member names. + member names. The ``value`` and ``name`` attributes are implemented this + way. :func:`unique` @@ -169,7 +170,7 @@ Data Types final *enum*, as well as creating the enum members, properly handling duplicates, providing iteration over the enum class, etc. - .. method:: EnumType.__call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None) + .. method:: EnumType.__call__(cls, value, names=None, \*, module=None, qualname=None, type=None, start=1, boundary=None) This method is called in two different ways: @@ -317,7 +318,7 @@ Data Types >>> PowersOfThree.SECOND.value 9 - .. method:: Enum.__init_subclass__(cls, **kwds) + .. method:: Enum.__init_subclass__(cls, \**kwds) A *classmethod* that is used to further configure subsequent subclasses. By default, does nothing. diff --git a/Lib/enum.py b/Lib/enum.py index e9f224a303d3..6e497f7ef6a7 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -190,6 +190,8 @@ class property(DynamicClassAttribute): """ member = None + _attr_type = None + _cls_type = None def __get__(self, instance, ownerclass=None): if instance is None: @@ -199,33 +201,36 @@ def __get__(self, instance, ownerclass=None): raise AttributeError( '%r has no attribute %r' % (ownerclass, self.name) ) - else: - if self.fget is None: - # look for a member by this name. - try: - return ownerclass._member_map_[self.name] - except KeyError: - raise AttributeError( - '%r has no attribute %r' % (ownerclass, self.name) - ) from None - else: - return self.fget(instance) + if self.fget is not None: + # use previous enum.property + return self.fget(instance) + elif self._attr_type == 'attr': + # look up previous attibute + return getattr(self._cls_type, self.name) + elif self._attr_type == 'desc': + # use previous descriptor + return getattr(instance._value_, self.name) + # look for a member by this name. + try: + return ownerclass._member_map_[self.name] + except KeyError: + raise AttributeError( + '%r has no attribute %r' % (ownerclass, self.name) + ) from None def __set__(self, instance, value): - if self.fset is None: - raise AttributeError( - " cannot set attribute %r" % (self.clsname, self.name) - ) - else: + if self.fset is not None: return self.fset(instance, value) + raise AttributeError( + " cannot set attribute %r" % (self.clsname, self.name) + ) def __delete__(self, instance): - if self.fdel is None: - raise AttributeError( - " cannot delete attribute %r" % (self.clsname, self.name) - ) - else: + if self.fdel is not None: return self.fdel(instance) + raise AttributeError( + " cannot delete attribute %r" % (self.clsname, self.name) + ) def __set_name__(self, ownerclass, name): self.name = name @@ -313,27 +318,38 @@ def __set_name__(self, enum_class, member_name): enum_class._member_names_.append(member_name) # if necessary, get redirect in place and then add it to _member_map_ found_descriptor = None + descriptor_type = None + class_type = None for base in enum_class.__mro__[1:]: - descriptor = base.__dict__.get(member_name) - if descriptor is not None: - if isinstance(descriptor, (property, DynamicClassAttribute)): - found_descriptor = descriptor + attr = base.__dict__.get(member_name) + if attr is not None: + if isinstance(attr, (property, DynamicClassAttribute)): + found_descriptor = attr + class_type = base + descriptor_type = 'enum' break - elif ( - hasattr(descriptor, 'fget') and - hasattr(descriptor, 'fset') and - hasattr(descriptor, 'fdel') - ): - found_descriptor = descriptor + elif _is_descriptor(attr): + found_descriptor = attr + descriptor_type = descriptor_type or 'desc' + class_type = class_type or base continue + else: + descriptor_type = 'attr' + class_type = base if found_descriptor: redirect = property() redirect.member = enum_member redirect.__set_name__(enum_class, member_name) - # earlier descriptor found; copy fget, fset, fdel to this one. - redirect.fget = found_descriptor.fget - redirect.fset = found_descriptor.fset - redirect.fdel = found_descriptor.fdel + if descriptor_type in ('enum','desc'): + # earlier descriptor found; copy fget, fset, fdel to this one. + redirect.fget = getattr(found_descriptor, 'fget', None) + redirect._get = getattr(found_descriptor, '__get__', None) + redirect.fset = getattr(found_descriptor, 'fset', None) + redirect._set = getattr(found_descriptor, '__set__', None) + redirect.fdel = getattr(found_descriptor, 'fdel', None) + redirect._del = getattr(found_descriptor, '__delete__', None) + redirect._attr_type = descriptor_type + redirect._cls_type = class_type setattr(enum_class, member_name, redirect) else: setattr(enum_class, member_name, enum_member) diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index e9dfcf8586a8..fb7a016c9007 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -819,10 +819,27 @@ class TestPlainFlag(_EnumTests, _PlainOutputTests, _FlagTests, unittest.TestCase class TestIntEnum(_EnumTests, _MinimalOutputTests, unittest.TestCase): enum_type = IntEnum + # + def test_shadowed_attr(self): + class Number(IntEnum): + divisor = 1 + numerator = 2 + # + self.assertEqual(Number.divisor.numerator, 1) + self.assertIs(Number.numerator.divisor, Number.divisor) class TestStrEnum(_EnumTests, _MinimalOutputTests, unittest.TestCase): enum_type = StrEnum + # + def test_shadowed_attr(self): + class Book(StrEnum): + author = 'author' + title = 'title' + # + self.assertEqual(Book.author.title(), 'Author') + self.assertEqual(Book.title.title(), 'Title') + self.assertIs(Book.title.author, Book.author) class TestIntFlag(_EnumTests, _MinimalOutputTests, _FlagTests, unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-04-17-14-47-28.gh-issue-103596.ME1y3_.rst b/Misc/NEWS.d/next/Library/2023-04-17-14-47-28.gh-issue-103596.ME1y3_.rst new file mode 100644 index 000000000000..2fa27e60b58e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-17-14-47-28.gh-issue-103596.ME1y3_.rst @@ -0,0 +1,2 @@ +Attributes/methods are no longer shadowed by same-named enum members, +although they may be shadowed by enum.property's. From webhook-mailer at python.org Tue Apr 18 22:31:40 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Wed, 19 Apr 2023 02:31:40 -0000 Subject: [Python-checkins] gh-103617: Fix compiler warning in _iomodule.c (#103618) Message-ID: https://github.com/python/cpython/commit/ffdbfe197694cb6f2509b94859ccf3534daa6fd1 commit: ffdbfe197694cb6f2509b94859ccf3534daa6fd1 branch: main author: Erlend E. Aasland committer: erlend-aasland date: 2023-04-18T20:30:54-06:00 summary: gh-103617: Fix compiler warning in _iomodule.c (#103618) files: M Modules/_io/_iomodule.c diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 5644cc05c458..7f4f1d939fb7 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -616,8 +616,9 @@ iomodule_clear(PyObject *mod) { } static void -iomodule_free(PyObject *mod) { - iomodule_clear(mod); +iomodule_free(void *mod) +{ + (void)iomodule_clear((PyObject *)mod); } From webhook-mailer at python.org Tue Apr 18 23:08:22 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Wed, 19 Apr 2023 03:08:22 -0000 Subject: [Python-checkins] gh-103583: Always pass multibyte codec structs as const (#103588) Message-ID: https://github.com/python/cpython/commit/e989e0b62aba9b487faf24d8694d28022d35a776 commit: e989e0b62aba9b487faf24d8694d28022d35a776 branch: main author: Erlend E. Aasland committer: erlend-aasland date: 2023-04-18T21:08:16-06:00 summary: gh-103583: Always pass multibyte codec structs as const (#103588) files: M Modules/cjkcodecs/multibytecodec.c M Modules/cjkcodecs/multibytecodec.h diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c index 55778cdb59e4..c42daefbd328 100644 --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -67,7 +67,7 @@ typedef struct { static char *incnewkwarglist[] = {"errors", NULL}; static char *streamkwarglist[] = {"stream", "errors", NULL}; -static PyObject *multibytecodec_encode(MultibyteCodec *, +static PyObject *multibytecodec_encode(const MultibyteCodec *, MultibyteCodec_State *, PyObject *, Py_ssize_t *, PyObject *, int); @@ -221,7 +221,7 @@ expand_encodebuffer(MultibyteEncodeBuffer *buf, Py_ssize_t esize) */ static int -multibytecodec_encerror(MultibyteCodec *codec, +multibytecodec_encerror(const MultibyteCodec *codec, MultibyteCodec_State *state, MultibyteEncodeBuffer *buf, PyObject *errors, Py_ssize_t e) @@ -375,7 +375,7 @@ multibytecodec_encerror(MultibyteCodec *codec, } static int -multibytecodec_decerror(MultibyteCodec *codec, +multibytecodec_decerror(const MultibyteCodec *codec, MultibyteCodec_State *state, MultibyteDecodeBuffer *buf, PyObject *errors, Py_ssize_t e) @@ -479,7 +479,7 @@ multibytecodec_decerror(MultibyteCodec *codec, } static PyObject * -multibytecodec_encode(MultibyteCodec *codec, +multibytecodec_encode(const MultibyteCodec *codec, MultibyteCodec_State *state, PyObject *text, Py_ssize_t *inpos_t, PyObject *errors, int flags) @@ -1953,7 +1953,7 @@ _multibytecodec___create_codec(PyObject *module, PyObject *arg) /*[clinic end generated code: output=cfa3dce8260e809d input=6840b2a6b183fcfa]*/ { MultibyteCodecObject *self; - MultibyteCodec *codec; + const MultibyteCodec *codec; if (!PyCapsule_IsValid(arg, PyMultibyteCodec_CAPSULE_NAME)) { PyErr_SetString(PyExc_ValueError, "argument type invalid"); diff --git a/Modules/cjkcodecs/multibytecodec.h b/Modules/cjkcodecs/multibytecodec.h index 69404ba96aa1..a6ab9cbe61a2 100644 --- a/Modules/cjkcodecs/multibytecodec.h +++ b/Modules/cjkcodecs/multibytecodec.h @@ -62,14 +62,14 @@ typedef struct { typedef struct { PyObject_HEAD - MultibyteCodec *codec; + const MultibyteCodec *codec; } MultibyteCodecObject; #define MultibyteCodec_Check(state, op) Py_IS_TYPE((op), state->multibytecodec_type) #define _MultibyteStatefulCodec_HEAD \ PyObject_HEAD \ - MultibyteCodec *codec; \ + const MultibyteCodec *codec; \ MultibyteCodec_State state; \ PyObject *errors; typedef struct { From webhook-mailer at python.org Wed Apr 19 01:02:55 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Wed, 19 Apr 2023 05:02:55 -0000 Subject: [Python-checkins] gh-103582: Remove last references to `argparse.REMAINDER` from docs (#103586) Message-ID: https://github.com/python/cpython/commit/f4d087964e3deaabc902a155efdf0e7f43f78d52 commit: f4d087964e3deaabc902a155efdf0e7f43f78d52 branch: main author: Nikita Sobolev committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-04-18T23:02:48-06:00 summary: gh-103582: Remove last references to `argparse.REMAINDER` from docs (#103586) files: M Doc/library/argparse.rst diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index ee68ac58d3de..dd59181a3070 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -67,7 +67,7 @@ default_ Default value used when an argument is not provided dest_ Specify the attribute name used in the result namespace help_ Help message for an argument metavar_ Alternate display name for the argument as shown in help -nargs_ Number of times the argument can be used :class:`int`, ``'?'``, ``'*'``, ``'+'``, or ``argparse.REMAINDER`` +nargs_ Number of times the argument can be used :class:`int`, ``'?'``, ``'*'``, or ``'+'`` required_ Indicate whether an argument is required or optional ``True`` or ``False`` type_ Automatically convert an argument to the given type :class:`int`, :class:`float`, ``argparse.FileType('w')``, or callable function ====================== =========================================================== ========================================================================================================================== @@ -2218,7 +2218,7 @@ support this parsing style. These parsers do not support all the argparse features, and will raise exceptions if unsupported features are used. In particular, subparsers, -``argparse.REMAINDER``, and mutually exclusive groups that include both +and mutually exclusive groups that include both optionals and positionals are not supported. The following example shows the difference between From webhook-mailer at python.org Wed Apr 19 01:06:00 2023 From: webhook-mailer at python.org (terryjreedy) Date: Wed, 19 Apr 2023 05:06:00 -0000 Subject: [Python-checkins] gh-102778: IDLE - make sys.last_exc available in Shell after traceback (#103314) Message-ID: https://github.com/python/cpython/commit/d1e4917e06d5638f1a7fa189d6d63ec9c2a27753 commit: d1e4917e06d5638f1a7fa189d6d63ec9c2a27753 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: terryjreedy date: 2023-04-19T01:05:52-04:00 summary: gh-102778: IDLE - make sys.last_exc available in Shell after traceback (#103314) --------- Co-authored-by: Terry Jan Reedy files: A Misc/NEWS.d/next/Library/2023-04-06-16-55-51.gh-issue-102778.BWeAmE.rst M Lib/idlelib/run.py diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 577c49eb67b2..04ce615621ee 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -239,6 +239,7 @@ def print_exception(): efile = sys.stderr typ, val, tb = excinfo = sys.exc_info() sys.last_type, sys.last_value, sys.last_traceback = excinfo + sys.last_exc = val seen = set() def print_exc(typ, exc, tb): diff --git a/Misc/NEWS.d/next/Library/2023-04-06-16-55-51.gh-issue-102778.BWeAmE.rst b/Misc/NEWS.d/next/Library/2023-04-06-16-55-51.gh-issue-102778.BWeAmE.rst new file mode 100644 index 000000000000..64ae5b5b6d56 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-06-16-55-51.gh-issue-102778.BWeAmE.rst @@ -0,0 +1 @@ +Support ``sys.last_exc`` in :mod:`idlelib`. From webhook-mailer at python.org Wed Apr 19 01:15:06 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 19 Apr 2023 05:15:06 -0000 Subject: [Python-checkins] gh-103582: Remove last references to `argparse.REMAINDER` from docs (GH-103586) Message-ID: https://github.com/python/cpython/commit/5a81a24c8b0fdb835831ecb14b0201d0a06bb84e commit: 5a81a24c8b0fdb835831ecb14b0201d0a06bb84e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-18T22:14:53-07:00 summary: gh-103582: Remove last references to `argparse.REMAINDER` from docs (GH-103586) (cherry picked from commit f4d087964e3deaabc902a155efdf0e7f43f78d52) Co-authored-by: Nikita Sobolev files: M Doc/library/argparse.rst diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 8dfe86a4add3..df283dbc9f5b 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -67,7 +67,7 @@ default_ Default value used when an argument is not provided dest_ Specify the attribute name used in the result namespace help_ Help message for an argument metavar_ Alternate display name for the argument as shown in help -nargs_ Number of times the argument can be used :class:`int`, ``'?'``, ``'*'``, ``'+'``, or ``argparse.REMAINDER`` +nargs_ Number of times the argument can be used :class:`int`, ``'?'``, ``'*'``, or ``'+'`` required_ Indicate whether an argument is required or optional ``True`` or ``False`` type_ Automatically convert an argument to the given type :class:`int`, :class:`float`, ``argparse.FileType('w')``, or callable function ====================== =========================================================== ========================================================================================================================== @@ -2186,7 +2186,7 @@ support this parsing style. These parsers do not support all the argparse features, and will raise exceptions if unsupported features are used. In particular, subparsers, -``argparse.REMAINDER``, and mutually exclusive groups that include both +and mutually exclusive groups that include both optionals and positionals are not supported. The following example shows the difference between From webhook-mailer at python.org Wed Apr 19 06:22:10 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Wed, 19 Apr 2023 10:22:10 -0000 Subject: [Python-checkins] GH-88342: clarify that `asyncio.as_completed` accepts generators yielding tasks (#103626) Message-ID: https://github.com/python/cpython/commit/da2273fec7b1644786b9616592b53b04fdec4024 commit: da2273fec7b1644786b9616592b53b04fdec4024 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-04-19T15:51:53+05:30 summary: GH-88342: clarify that `asyncio.as_completed` accepts generators yielding tasks (#103626) files: M Doc/library/asyncio-task.rst M Doc/whatsnew/3.12.rst diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 41d09e1e7970..b81d89acf7fd 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -829,6 +829,9 @@ Waiting Primitives Deprecation warning is emitted if not all awaitable objects in the *aws* iterable are Future-like objects and there is no running event loop. + .. versionchanged:: 3.12 + Added support for generators yielding tasks. + Running in Threads ================== diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index bd95bfeea80c..b3bb065741d0 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -250,7 +250,8 @@ asyncio :mod:`asyncio` does not support legacy generator-based coroutines. (Contributed by Kumar Aditya in :gh:`102748`.) -* :func:`asyncio.wait` now accepts generators yielding tasks. +* :func:`asyncio.wait` and :func:`asyncio.as_completed` now accepts generators + yielding tasks. (Contributed by Kumar Aditya in :gh:`78530`.) csv From webhook-mailer at python.org Wed Apr 19 10:15:59 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Wed, 19 Apr 2023 14:15:59 -0000 Subject: [Python-checkins] gh-83004: Harden msvcrt further (#103420) Message-ID: https://github.com/python/cpython/commit/bd2ed066c855dadbc739e89f9bc32e218dfc904e commit: bd2ed066c855dadbc739e89f9bc32e218dfc904e branch: main author: Erlend E. Aasland committer: erlend-aasland date: 2023-04-19T08:15:50-06:00 summary: gh-83004: Harden msvcrt further (#103420) files: M PC/msvcrtmodule.c diff --git a/PC/msvcrtmodule.c b/PC/msvcrtmodule.c index de9a88946aff..090254befc93 100644 --- a/PC/msvcrtmodule.c +++ b/PC/msvcrtmodule.c @@ -564,88 +564,81 @@ static struct PyMethodDef msvcrt_functions[] = { {NULL, NULL} }; -static void -insertint(PyObject *d, char *name, int value) -{ - PyObject *v = PyLong_FromLong((long) value); - if (v == NULL) { - /* Don't bother reporting this error */ - PyErr_Clear(); - } - else { - PyDict_SetItemString(d, name, v); - Py_DECREF(v); - } -} - -static void -insertptr(PyObject *d, char *name, void *value) +static int +insertptr(PyObject *mod, char *name, void *value) { PyObject *v = PyLong_FromVoidPtr(value); if (v == NULL) { - /* Don't bother reporting this error */ - PyErr_Clear(); - } - else { - PyDict_SetItemString(d, name, v); - Py_DECREF(v); + return -1; } + int rc = PyModule_AddObjectRef(mod, name, v); + Py_DECREF(v); + return rc; } +#define INSERTINT(MOD, NAME, VAL) do { \ + if (PyModule_AddIntConstant(MOD, NAME, VAL) < 0) { \ + return -1; \ + } \ +} while (0) + +#define INSERTPTR(MOD, NAME, PTR) do { \ + if (insertptr(MOD, NAME, PTR) < 0) { \ + return -1; \ + } \ +} while (0) + +#define INSERTSTR(MOD, NAME, CONST) do { \ + if (PyModule_AddStringConstant(MOD, NAME, CONST) < 0) { \ + return -1; \ + } \ +} while (0) + static int exec_module(PyObject* m) { - int st; - PyObject *d = PyModule_GetDict(m); // Borrowed ref. - /* constants for the locking() function's mode argument */ - insertint(d, "LK_LOCK", _LK_LOCK); - insertint(d, "LK_NBLCK", _LK_NBLCK); - insertint(d, "LK_NBRLCK", _LK_NBRLCK); - insertint(d, "LK_RLCK", _LK_RLCK); - insertint(d, "LK_UNLCK", _LK_UNLCK); + INSERTINT(m, "LK_LOCK", _LK_LOCK); + INSERTINT(m, "LK_NBLCK", _LK_NBLCK); + INSERTINT(m, "LK_NBRLCK", _LK_NBRLCK); + INSERTINT(m, "LK_RLCK", _LK_RLCK); + INSERTINT(m, "LK_UNLCK", _LK_UNLCK); #ifdef MS_WINDOWS_DESKTOP - insertint(d, "SEM_FAILCRITICALERRORS", SEM_FAILCRITICALERRORS); - insertint(d, "SEM_NOALIGNMENTFAULTEXCEPT", SEM_NOALIGNMENTFAULTEXCEPT); - insertint(d, "SEM_NOGPFAULTERRORBOX", SEM_NOGPFAULTERRORBOX); - insertint(d, "SEM_NOOPENFILEERRORBOX", SEM_NOOPENFILEERRORBOX); + INSERTINT(m, "SEM_FAILCRITICALERRORS", SEM_FAILCRITICALERRORS); + INSERTINT(m, "SEM_NOALIGNMENTFAULTEXCEPT", SEM_NOALIGNMENTFAULTEXCEPT); + INSERTINT(m, "SEM_NOGPFAULTERRORBOX", SEM_NOGPFAULTERRORBOX); + INSERTINT(m, "SEM_NOOPENFILEERRORBOX", SEM_NOOPENFILEERRORBOX); #endif #ifdef _DEBUG - insertint(d, "CRT_WARN", _CRT_WARN); - insertint(d, "CRT_ERROR", _CRT_ERROR); - insertint(d, "CRT_ASSERT", _CRT_ASSERT); - insertint(d, "CRTDBG_MODE_DEBUG", _CRTDBG_MODE_DEBUG); - insertint(d, "CRTDBG_MODE_FILE", _CRTDBG_MODE_FILE); - insertint(d, "CRTDBG_MODE_WNDW", _CRTDBG_MODE_WNDW); - insertint(d, "CRTDBG_REPORT_MODE", _CRTDBG_REPORT_MODE); - insertptr(d, "CRTDBG_FILE_STDERR", _CRTDBG_FILE_STDERR); - insertptr(d, "CRTDBG_FILE_STDOUT", _CRTDBG_FILE_STDOUT); - insertptr(d, "CRTDBG_REPORT_FILE", _CRTDBG_REPORT_FILE); + INSERTINT(m, "CRT_WARN", _CRT_WARN); + INSERTINT(m, "CRT_ERROR", _CRT_ERROR); + INSERTINT(m, "CRT_ASSERT", _CRT_ASSERT); + INSERTINT(m, "CRTDBG_MODE_DEBUG", _CRTDBG_MODE_DEBUG); + INSERTINT(m, "CRTDBG_MODE_FILE", _CRTDBG_MODE_FILE); + INSERTINT(m, "CRTDBG_MODE_WNDW", _CRTDBG_MODE_WNDW); + INSERTINT(m, "CRTDBG_REPORT_MODE", _CRTDBG_REPORT_MODE); + INSERTPTR(m, "CRTDBG_FILE_STDERR", _CRTDBG_FILE_STDERR); + INSERTPTR(m, "CRTDBG_FILE_STDOUT", _CRTDBG_FILE_STDOUT); + INSERTPTR(m, "CRTDBG_REPORT_FILE", _CRTDBG_REPORT_FILE); #endif +#undef INSERTINT +#undef INSERTPTR + /* constants for the crt versions */ #ifdef _VC_ASSEMBLY_PUBLICKEYTOKEN - st = PyModule_AddStringConstant(m, "VC_ASSEMBLY_PUBLICKEYTOKEN", - _VC_ASSEMBLY_PUBLICKEYTOKEN); - if (st < 0) { - return -1; - } + INSERTSTR(m, "VC_ASSEMBLY_PUBLICKEYTOKEN", _VC_ASSEMBLY_PUBLICKEYTOKEN); #endif #ifdef _CRT_ASSEMBLY_VERSION - st = PyModule_AddStringConstant(m, "CRT_ASSEMBLY_VERSION", - _CRT_ASSEMBLY_VERSION); - if (st < 0) { - return -1; - } + INSERTSTR(m, "CRT_ASSEMBLY_VERSION", _CRT_ASSEMBLY_VERSION); #endif #ifdef __LIBRARIES_ASSEMBLY_NAME_PREFIX - st = PyModule_AddStringConstant(m, "LIBRARIES_ASSEMBLY_NAME_PREFIX", - __LIBRARIES_ASSEMBLY_NAME_PREFIX); - if (st < 0) { - return -1; - } + INSERTSTR(m, "LIBRARIES_ASSEMBLY_NAME_PREFIX", + __LIBRARIES_ASSEMBLY_NAME_PREFIX); #endif +#undef INSERTSTR + /* constants for the 2010 crt versions */ #if defined(_VC_CRT_MAJOR_VERSION) && defined (_VC_CRT_MINOR_VERSION) && defined(_VC_CRT_BUILD_VERSION) && defined(_VC_CRT_RBUILD_VERSION) PyObject *version = PyUnicode_FromFormat("%d.%d.%d.%d", @@ -656,14 +649,12 @@ exec_module(PyObject* m) if (version == NULL) { return -1; } - st = PyModule_AddObjectRef(m, "CRT_ASSEMBLY_VERSION", version); + int st = PyModule_AddObjectRef(m, "CRT_ASSEMBLY_VERSION", version); Py_DECREF(version); if (st < 0) { return -1; } #endif - /* make compiler warning quiet if st is unused */ - (void)st; return 0; } From webhook-mailer at python.org Wed Apr 19 10:37:26 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 19 Apr 2023 14:37:26 -0000 Subject: [Python-checkins] Doc: Fix broken link to emscripten networking website (GH-99531) Message-ID: https://github.com/python/cpython/commit/2b5dbd1f237a013defdaf0799e0a1a3cbd0b13cc commit: 2b5dbd1f237a013defdaf0799e0a1a3cbd0b13cc branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-19T07:37:14-07:00 summary: Doc: Fix broken link to emscripten networking website (GH-99531) There was an extra `>` in the url. (cherry picked from commit ed206e39f02e93cc53e485655d84aaed6b40e0e6) Co-authored-by: Alexander Ryabov <73594+haron at users.noreply.github.com> files: M Doc/library/intro.rst diff --git a/Doc/library/intro.rst b/Doc/library/intro.rst index 1020924038e9..5a4c9b8b16ab 100644 --- a/Doc/library/intro.rst +++ b/Doc/library/intro.rst @@ -114,7 +114,7 @@ DOM APIs as well as limited networking capabilities with JavaScript's .. _WebAssembly: https://webassembly.org/ .. _Emscripten: https://emscripten.org/ -.. _Emscripten Networking: https://emscripten.org/docs/porting/networking.html> +.. _Emscripten Networking: https://emscripten.org/docs/porting/networking.html .. _WASI: https://wasi.dev/ .. _wasmtime: https://wasmtime.dev/ .. _Pyodide: https://pyodide.org/ From webhook-mailer at python.org Wed Apr 19 12:02:24 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Wed, 19 Apr 2023 16:02:24 -0000 Subject: [Python-checkins] gh-103583: Add ref. dependency between multibytecodec modules (#103589) Message-ID: https://github.com/python/cpython/commit/a6b07b5a345f7f54ee9f6d75e81d2fb55971b35c commit: a6b07b5a345f7f54ee9f6d75e81d2fb55971b35c branch: main author: Erlend E. Aasland committer: erlend-aasland date: 2023-04-19T10:02:17-06:00 summary: gh-103583: Add ref. dependency between multibytecodec modules (#103589) files: M Modules/cjkcodecs/cjkcodecs.h M Modules/cjkcodecs/multibytecodec.c M Modules/cjkcodecs/multibytecodec.h diff --git a/Modules/cjkcodecs/cjkcodecs.h b/Modules/cjkcodecs/cjkcodecs.h index 646a9fd255ce..1b0355310edd 100644 --- a/Modules/cjkcodecs/cjkcodecs.h +++ b/Modules/cjkcodecs/cjkcodecs.h @@ -284,18 +284,45 @@ getmultibytecodec(void) return _PyImport_GetModuleAttrString("_multibytecodec", "__create_codec"); } +static void +destroy_codec_capsule(PyObject *capsule) +{ + void *ptr = PyCapsule_GetPointer(capsule, CODEC_CAPSULE); + codec_capsule *data = (codec_capsule *)ptr; + Py_DECREF(data->cjk_module); + PyMem_Free(ptr); +} + +static codec_capsule * +capsulate_codec(PyObject *mod, const MultibyteCodec *codec) +{ + codec_capsule *data = PyMem_Malloc(sizeof(codec_capsule)); + if (data == NULL) { + PyErr_NoMemory(); + return NULL; + } + data->codec = codec; + data->cjk_module = Py_NewRef(mod); + return data; +} + static PyObject * -_getcodec(const MultibyteCodec *codec) +_getcodec(PyObject *self, const MultibyteCodec *codec) { PyObject *cofunc = getmultibytecodec(); if (cofunc == NULL) { return NULL; } - PyObject *codecobj = PyCapsule_New((void *)codec, - PyMultibyteCodec_CAPSULE_NAME, - NULL); + codec_capsule *data = capsulate_codec(self, codec); + if (data == NULL) { + Py_DECREF(cofunc); + return NULL; + } + PyObject *codecobj = PyCapsule_New(data, CODEC_CAPSULE, + destroy_codec_capsule); if (codecobj == NULL) { + PyMem_Free(data); Py_DECREF(cofunc); return NULL; } @@ -323,7 +350,7 @@ getcodec(PyObject *self, PyObject *encoding) for (int i = 0; i < st->num_codecs; i++) { const MultibyteCodec *codec = &st->codec_list[i]; if (strcmp(codec->encoding, enc) == 0) { - return _getcodec(codec); + return _getcodec(self, codec); } } @@ -352,8 +379,7 @@ register_maps(PyObject *module) char mhname[256] = "__map_"; strcpy(mhname + sizeof("__map_") - 1, h->charset); - PyObject *capsule = PyCapsule_New((void *)h, - PyMultibyteCodec_CAPSULE_NAME, NULL); + PyObject *capsule = PyCapsule_New((void *)h, MAP_CAPSULE, NULL); if (capsule == NULL) { return -1; } @@ -417,14 +443,14 @@ importmap(const char *modname, const char *symbol, o = PyObject_GetAttrString(mod, symbol); if (o == NULL) goto errorexit; - else if (!PyCapsule_IsValid(o, PyMultibyteCodec_CAPSULE_NAME)) { + else if (!PyCapsule_IsValid(o, MAP_CAPSULE)) { PyErr_SetString(PyExc_ValueError, "map data must be a Capsule."); goto errorexit; } else { struct dbcs_map *map; - map = PyCapsule_GetPointer(o, PyMultibyteCodec_CAPSULE_NAME); + map = PyCapsule_GetPointer(o, MAP_CAPSULE); if (encmap != NULL) *encmap = map->encmap; if (decmap != NULL) diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c index c42daefbd328..8976ad331aaa 100644 --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -720,9 +720,17 @@ static struct PyMethodDef multibytecodec_methods[] = { }; static int -multibytecodec_traverse(PyObject *self, visitproc visit, void *arg) +multibytecodec_clear(MultibyteCodecObject *self) +{ + Py_CLEAR(self->cjk_module); + return 0; +} + +static int +multibytecodec_traverse(MultibyteCodecObject *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->cjk_module); return 0; } @@ -731,6 +739,7 @@ multibytecodec_dealloc(MultibyteCodecObject *self) { PyObject_GC_UnTrack(self); PyTypeObject *tp = Py_TYPE(self); + (void)multibytecodec_clear(self); tp->tp_free(self); Py_DECREF(tp); } @@ -740,6 +749,7 @@ static PyType_Slot multibytecodec_slots[] = { {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_methods, multibytecodec_methods}, {Py_tp_traverse, multibytecodec_traverse}, + {Py_tp_clear, multibytecodec_clear}, {0, NULL}, }; @@ -1953,14 +1963,14 @@ _multibytecodec___create_codec(PyObject *module, PyObject *arg) /*[clinic end generated code: output=cfa3dce8260e809d input=6840b2a6b183fcfa]*/ { MultibyteCodecObject *self; - const MultibyteCodec *codec; - if (!PyCapsule_IsValid(arg, PyMultibyteCodec_CAPSULE_NAME)) { + if (!PyCapsule_IsValid(arg, CODEC_CAPSULE)) { PyErr_SetString(PyExc_ValueError, "argument type invalid"); return NULL; } - codec = PyCapsule_GetPointer(arg, PyMultibyteCodec_CAPSULE_NAME); + codec_capsule *data = PyCapsule_GetPointer(arg, CODEC_CAPSULE); + const MultibyteCodec *codec = data->codec; if (codec->codecinit != NULL && codec->codecinit(codec->config) != 0) return NULL; @@ -1969,6 +1979,7 @@ _multibytecodec___create_codec(PyObject *module, PyObject *arg) if (self == NULL) return NULL; self->codec = codec; + self->cjk_module = Py_NewRef(data->cjk_module); PyObject_GC_Track(self); return (PyObject *)self; diff --git a/Modules/cjkcodecs/multibytecodec.h b/Modules/cjkcodecs/multibytecodec.h index a6ab9cbe61a2..327cb51129d9 100644 --- a/Modules/cjkcodecs/multibytecodec.h +++ b/Modules/cjkcodecs/multibytecodec.h @@ -63,6 +63,7 @@ typedef struct { typedef struct { PyObject_HEAD const MultibyteCodec *codec; + PyObject *cjk_module; } MultibyteCodecObject; #define MultibyteCodec_Check(state, op) Py_IS_TYPE((op), state->multibytecodec_type) @@ -130,7 +131,13 @@ typedef struct { #define MBENC_FLUSH 0x0001 /* encode all characters encodable */ #define MBENC_MAX MBENC_FLUSH -#define PyMultibyteCodec_CAPSULE_NAME "multibytecodec.__map_*" +typedef struct { + const MultibyteCodec *codec; + PyObject *cjk_module; +} codec_capsule; + +#define MAP_CAPSULE "multibytecodec.map" +#define CODEC_CAPSULE "multibytecodec.codec" #ifdef __cplusplus From webhook-mailer at python.org Wed Apr 19 12:18:26 2023 From: webhook-mailer at python.org (pablogsal) Date: Wed, 19 Apr 2023 16:18:26 -0000 Subject: [Python-checkins] gh-102856: Initial implementation of PEP 701 (#102855) Message-ID: https://github.com/python/cpython/commit/1ef61cf71a218c71860ff6aecf0fd51edb8b65dc commit: 1ef61cf71a218c71860ff6aecf0fd51edb8b65dc branch: main author: Pablo Galindo Salgado committer: pablogsal date: 2023-04-19T11:18:16-05:00 summary: gh-102856: Initial implementation of PEP 701 (#102855) Co-authored-by: Lysandros Nikolaou Co-authored-by: Batuhan Taskaya Co-authored-by: Marta G?mez Mac?as Co-authored-by: sunmy2019 <59365878+sunmy2019 at users.noreply.github.com> files: A Misc/NEWS.d/next/Core and Builtins/2023-04-17-16-00-32.gh-issue-102856.UunJ7y.rst M Doc/library/token-list.inc M Grammar/Tokens M Grammar/python.gram M Include/internal/pycore_token.h M Lib/test/test_ast.py M Lib/test/test_cmd_line_script.py M Lib/test/test_eof.py M Lib/test/test_exceptions.py M Lib/test/test_fstring.py M Lib/test/test_tokenize.py M Lib/test/test_type_comments.py M Lib/token.py M Parser/action_helpers.c M Parser/parser.c M Parser/pegen.c M Parser/pegen.h M Parser/pegen_errors.c M Parser/string_parser.c M Parser/string_parser.h M Parser/token.c M Parser/tokenizer.c M Parser/tokenizer.h M Programs/test_frozenmain.h M Python/Python-tokenize.c M Tools/build/generate_token.py M Tools/peg_generator/pegen/c_generator.py diff --git a/Doc/library/token-list.inc b/Doc/library/token-list.inc index 2739d5bfc1df..3b345099bf54 100644 --- a/Doc/library/token-list.inc +++ b/Doc/library/token-list.inc @@ -201,6 +201,10 @@ Token value for ``":="``. +.. data:: EXCLAMATION + + Token value for ``"!"``. + .. data:: OP .. data:: AWAIT @@ -213,6 +217,12 @@ .. data:: SOFT_KEYWORD +.. data:: FSTRING_START + +.. data:: FSTRING_MIDDLE + +.. data:: FSTRING_END + .. data:: ERRORTOKEN .. data:: N_TOKENS diff --git a/Grammar/Tokens b/Grammar/Tokens index 1f3e3b099136..096876fdd130 100644 --- a/Grammar/Tokens +++ b/Grammar/Tokens @@ -53,6 +53,7 @@ ATEQUAL '@=' RARROW '->' ELLIPSIS '...' COLONEQUAL ':=' +EXCLAMATION '!' OP AWAIT @@ -60,6 +61,9 @@ ASYNC TYPE_IGNORE TYPE_COMMENT SOFT_KEYWORD +FSTRING_START +FSTRING_MIDDLE +FSTRING_END ERRORTOKEN # These aren't used by the C tokenizer but are needed for tokenize.py diff --git a/Grammar/python.gram b/Grammar/python.gram index 2498251293e8..3a356c65a751 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -194,7 +194,7 @@ yield_stmt[stmt_ty]: y=yield_expr { _PyAST_Expr(y, EXTRA) } assert_stmt[stmt_ty]: 'assert' a=expression b=[',' z=expression { z }] { _PyAST_Assert(a, b, EXTRA) } -import_stmt[stmt_ty]: +import_stmt[stmt_ty]: | invalid_import | import_name | import_from @@ -415,8 +415,8 @@ try_stmt[stmt_ty]: | invalid_try_stmt | 'try' &&':' b=block f=finally_block { _PyAST_Try(b, NULL, NULL, f, EXTRA) } | 'try' &&':' b=block ex[asdl_excepthandler_seq*]=except_block+ el=[else_block] f=[finally_block] { _PyAST_Try(b, ex, el, f, EXTRA) } - | 'try' &&':' b=block ex[asdl_excepthandler_seq*]=except_star_block+ el=[else_block] f=[finally_block] { - CHECK_VERSION(stmt_ty, 11, "Exception groups are", + | 'try' &&':' b=block ex[asdl_excepthandler_seq*]=except_star_block+ el=[else_block] f=[finally_block] { + CHECK_VERSION(stmt_ty, 11, "Exception groups are", _PyAST_TryStar(b, ex, el, f, EXTRA)) } @@ -807,7 +807,7 @@ atom[expr_ty]: | 'True' { _PyAST_Constant(Py_True, NULL, EXTRA) } | 'False' { _PyAST_Constant(Py_False, NULL, EXTRA) } | 'None' { _PyAST_Constant(Py_None, NULL, EXTRA) } - | &STRING strings + | &(STRING|FSTRING_START) strings | NUMBER | &'(' (tuple | group | genexp) | &'[' (list | listcomp) @@ -877,7 +877,26 @@ lambda_param[arg_ty]: a=NAME { _PyAST_arg(a->v.Name.id, NULL, NULL, EXTRA) } # LITERALS # ======== -strings[expr_ty] (memo): a=STRING+ { _PyPegen_concatenate_strings(p, a) } +fstring_middle[expr_ty]: + | fstring_replacement_field + | t=FSTRING_MIDDLE { _PyPegen_constant_from_token(p, t) } +fstring_replacement_field[expr_ty]: + | '{' a=(yield_expr | star_expressions) debug_expr="="? conversion=[fstring_conversion] format=[fstring_full_format_spec] '}' { + _PyPegen_formatted_value(p, a, debug_expr, conversion, format, EXTRA) + } + | invalid_replacement_field +fstring_conversion[expr_ty]: + | conv_token="!" conv=NAME { _PyPegen_check_fstring_conversion(p, conv_token, conv) } +fstring_full_format_spec[expr_ty]: + | ':' spec=fstring_format_spec* { spec ? _PyAST_JoinedStr((asdl_expr_seq*)spec, EXTRA) : NULL } +fstring_format_spec[expr_ty]: + | t=FSTRING_MIDDLE { _PyPegen_constant_from_token(p, t) } + | fstring_replacement_field +fstring[expr_ty]: + | a=FSTRING_START b=fstring_middle* c=FSTRING_END { _PyPegen_joined_str(p, a, (asdl_expr_seq*)b, c) } + +string[expr_ty]: s[Token*]=STRING { _PyPegen_constant_from_string(p, s) } +strings[expr_ty] (memo): a[asdl_expr_seq*]=(fstring|string)+ { _PyPegen_concatenate_strings(p, a, EXTRA) } list[expr_ty]: | '[' a=[star_named_expressions] ']' { _PyAST_List(a, Load, EXTRA) } @@ -1118,6 +1137,8 @@ invalid_expression: _PyPegen_check_legacy_stmt(p, a) ? NULL : p->tokens[p->mark-1]->level == 0 ? NULL : RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax. Perhaps you forgot a comma?") } | a=disjunction 'if' b=disjunction !('else'|':') { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "expected 'else' after 'if' expression") } + | a='lambda' [lambda_params] b=':' &(FSTRING_MIDDLE | fstring_replacement_field) { + RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "f-string: lambda expressions are not allowed without parentheses") } invalid_named_expression(memo): | a=expression ':=' expression { @@ -1241,7 +1262,7 @@ invalid_group: invalid_import: | a='import' dotted_name 'from' dotted_name { RAISE_SYNTAX_ERROR_STARTING_FROM(a, "Did you mean to use 'from ... import ...' instead?") } - + invalid_import_from_targets: | import_from_as_names ',' NEWLINE { RAISE_SYNTAX_ERROR("trailing comma not allowed without surrounding parentheses") } @@ -1335,3 +1356,24 @@ invalid_kvpair: | expression a=':' &('}'|',') {RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "expression expected after dictionary key and ':'") } invalid_starred_expression: | a='*' expression '=' b=expression { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot assign to iterable argument unpacking") } +invalid_replacement_field: + | '{' a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before '='") } + | '{' a='!' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before '!'") } + | '{' a=':' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before ':'") } + | '{' a='}' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before '}'") } + | '{' !(yield_expr | star_expressions) { RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting a valid expression after '{'")} + | '{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}') { + PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting '=', or '!', or ':', or '}'") } + | '{' (yield_expr | star_expressions) '=' !('!' | ':' | '}') { + PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting '!', or ':', or '}'") } + | '{' (yield_expr | star_expressions) '='? invalid_conversion_character + | '{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}') { + PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting ':' or '}'") } + | '{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}' { + PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting '}', or format specs") } + | '{' (yield_expr | star_expressions) '='? ['!' NAME] !'}' { + PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting '}'") } + +invalid_conversion_character: + | '!' &(':' | '}') { RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: missing conversion character") } + | '!' !NAME { RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: invalid conversion character") } diff --git a/Include/internal/pycore_token.h b/Include/internal/pycore_token.h index 95459ab9f7d0..b9df8766736a 100644 --- a/Include/internal/pycore_token.h +++ b/Include/internal/pycore_token.h @@ -67,14 +67,18 @@ extern "C" { #define RARROW 51 #define ELLIPSIS 52 #define COLONEQUAL 53 -#define OP 54 -#define AWAIT 55 -#define ASYNC 56 -#define TYPE_IGNORE 57 -#define TYPE_COMMENT 58 -#define SOFT_KEYWORD 59 -#define ERRORTOKEN 60 -#define N_TOKENS 64 +#define EXCLAMATION 54 +#define OP 55 +#define AWAIT 56 +#define ASYNC 57 +#define TYPE_IGNORE 58 +#define TYPE_COMMENT 59 +#define SOFT_KEYWORD 60 +#define FSTRING_START 61 +#define FSTRING_MIDDLE 62 +#define FSTRING_END 63 +#define ERRORTOKEN 64 +#define N_TOKENS 68 #define NT_OFFSET 256 /* Special definitions for cooperation with parser */ @@ -86,6 +90,8 @@ extern "C" { (x) == NEWLINE || \ (x) == INDENT || \ (x) == DEDENT) +#define ISSTRINGLIT(x) ((x) == STRING || \ + (x) == FSTRING_MIDDLE) // Symbols exported for test_peg_generator diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index 6c932e1305e1..a579bfd79307 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -774,11 +774,6 @@ def test_parenthesized_with_feature_version(self): ast.parse('with (CtxManager() as example): ...', feature_version=(3, 8)) ast.parse('with CtxManager() as example: ...', feature_version=(3, 8)) - def test_debug_f_string_feature_version(self): - ast.parse('f"{x=}"', feature_version=(3, 8)) - with self.assertRaises(SyntaxError): - ast.parse('f"{x=}"', feature_version=(3, 7)) - def test_assignment_expression_feature_version(self): ast.parse('(x := 0)', feature_version=(3, 8)) with self.assertRaises(SyntaxError): diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index f10d72ea5547..d98e23855e0c 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -636,9 +636,9 @@ def test_syntaxerror_multi_line_fstring(self): self.assertEqual( stderr.splitlines()[-3:], [ - b' foo"""', - b' ^', - b'SyntaxError: f-string: empty expression not allowed', + b' foo = f"""{}', + b' ^', + b'SyntaxError: f-string: valid expression required before \'}\'', ], ) diff --git a/Lib/test/test_eof.py b/Lib/test/test_eof.py index abcbf046e2cc..be4fd73bfdc3 100644 --- a/Lib/test/test_eof.py +++ b/Lib/test/test_eof.py @@ -4,6 +4,7 @@ from test import support from test.support import os_helper from test.support import script_helper +from test.support import warnings_helper import unittest class EOFTestCase(unittest.TestCase): @@ -36,10 +37,11 @@ def test_EOFS_with_file(self): rc, out, err = script_helper.assert_python_failure(file_name) self.assertIn(b'unterminated triple-quoted string literal (detected at line 3)', err) + @warnings_helper.ignore_warnings(category=SyntaxWarning) def test_eof_with_line_continuation(self): expect = "unexpected EOF while parsing (, line 1)" try: - compile('"\\xhh" \\', '', 'exec', dont_inherit=True) + compile('"\\Xhh" \\', '', 'exec') except SyntaxError as msg: self.assertEqual(str(msg), expect) else: diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 684e888f08c7..4ef7decfbc26 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -155,6 +155,7 @@ def ckmsg(src, msg): ckmsg(s, "'continue' not properly in loop") ckmsg("continue\n", "'continue' not properly in loop") + ckmsg("f'{6 0}'", "invalid syntax. Perhaps you forgot a comma?") def testSyntaxErrorMissingParens(self): def ckmsg(src, msg, exception=SyntaxError): @@ -227,7 +228,7 @@ def testSyntaxErrorOffset(self): check('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', 1, 20) check(b'# -*- coding: cp1251 -*-\nPython = "\xcf\xb3\xf2\xee\xed" +', 2, 19, encoding='cp1251') - check(b'Python = "\xcf\xb3\xf2\xee\xed" +', 1, 18) + check(b'Python = "\xcf\xb3\xf2\xee\xed" +', 1, 10) check('x = "a', 1, 5) check('lambda x: x = 2', 1, 1) check('f{a + b + c}', 1, 2) diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index b3f6ef41d77b..f571233da07b 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -329,13 +329,13 @@ def test_ast_line_numbers_multiline_fstring(self): self.assertEqual(t.body[1].lineno, 3) self.assertEqual(t.body[1].value.lineno, 3) self.assertEqual(t.body[1].value.values[0].lineno, 3) - self.assertEqual(t.body[1].value.values[1].lineno, 3) - self.assertEqual(t.body[1].value.values[2].lineno, 3) + self.assertEqual(t.body[1].value.values[1].lineno, 4) + self.assertEqual(t.body[1].value.values[2].lineno, 6) self.assertEqual(t.body[1].col_offset, 0) self.assertEqual(t.body[1].value.col_offset, 0) - self.assertEqual(t.body[1].value.values[0].col_offset, 0) - self.assertEqual(t.body[1].value.values[1].col_offset, 0) - self.assertEqual(t.body[1].value.values[2].col_offset, 0) + self.assertEqual(t.body[1].value.values[0].col_offset, 4) + self.assertEqual(t.body[1].value.values[1].col_offset, 2) + self.assertEqual(t.body[1].value.values[2].col_offset, 11) # NOTE: the following lineno information and col_offset is correct for # expressions within FormattedValues. binop = t.body[1].value.values[1].value @@ -366,13 +366,13 @@ def test_ast_line_numbers_multiline_fstring(self): self.assertEqual(t.body[0].lineno, 2) self.assertEqual(t.body[0].value.lineno, 2) self.assertEqual(t.body[0].value.values[0].lineno, 2) - self.assertEqual(t.body[0].value.values[1].lineno, 2) - self.assertEqual(t.body[0].value.values[2].lineno, 2) + self.assertEqual(t.body[0].value.values[1].lineno, 3) + self.assertEqual(t.body[0].value.values[2].lineno, 3) self.assertEqual(t.body[0].col_offset, 0) self.assertEqual(t.body[0].value.col_offset, 4) - self.assertEqual(t.body[0].value.values[0].col_offset, 4) - self.assertEqual(t.body[0].value.values[1].col_offset, 4) - self.assertEqual(t.body[0].value.values[2].col_offset, 4) + self.assertEqual(t.body[0].value.values[0].col_offset, 8) + self.assertEqual(t.body[0].value.values[1].col_offset, 10) + self.assertEqual(t.body[0].value.values[2].col_offset, 17) # Check {blech} self.assertEqual(t.body[0].value.values[1].value.lineno, 3) self.assertEqual(t.body[0].value.values[1].value.end_lineno, 3) @@ -387,6 +387,20 @@ def test_ast_line_numbers_with_parentheses(self): t = ast.parse(expr) self.assertEqual(type(t), ast.Module) self.assertEqual(len(t.body), 1) + # check the joinedstr location + joinedstr = t.body[0].value + self.assertEqual(type(joinedstr), ast.JoinedStr) + self.assertEqual(joinedstr.lineno, 3) + self.assertEqual(joinedstr.end_lineno, 3) + self.assertEqual(joinedstr.col_offset, 4) + self.assertEqual(joinedstr.end_col_offset, 17) + # check the formatted value location + fv = t.body[0].value.values[1] + self.assertEqual(type(fv), ast.FormattedValue) + self.assertEqual(fv.lineno, 3) + self.assertEqual(fv.end_lineno, 3) + self.assertEqual(fv.col_offset, 7) + self.assertEqual(fv.end_col_offset, 16) # check the test(t) location call = t.body[0].value.values[1].value self.assertEqual(type(call), ast.Call) @@ -397,6 +411,50 @@ def test_ast_line_numbers_with_parentheses(self): expr = """ x = ( + u'wat', + u"wat", + b'wat', + b"wat", + f'wat', + f"wat", +) + +y = ( + u'''wat''', + u\"\"\"wat\"\"\", + b'''wat''', + b\"\"\"wat\"\"\", + f'''wat''', + f\"\"\"wat\"\"\", +) + """ + t = ast.parse(expr) + self.assertEqual(type(t), ast.Module) + self.assertEqual(len(t.body), 2) + x, y = t.body + + # Check the single quoted string offsets first. + offsets = [ + (elt.col_offset, elt.end_col_offset) + for elt in x.value.elts + ] + self.assertTrue(all( + offset == (4, 10) + for offset in offsets + )) + + # Check the triple quoted string offsets. + offsets = [ + (elt.col_offset, elt.end_col_offset) + for elt in y.value.elts + ] + self.assertTrue(all( + offset == (4, 14) + for offset in offsets + )) + + expr = """ +x = ( 'PERL_MM_OPT', ( f'wat' f'some_string={f(x)} ' @@ -415,9 +473,9 @@ def test_ast_line_numbers_with_parentheses(self): # check the first wat self.assertEqual(type(wat1), ast.Constant) self.assertEqual(wat1.lineno, 4) - self.assertEqual(wat1.end_lineno, 6) - self.assertEqual(wat1.col_offset, 12) - self.assertEqual(wat1.end_col_offset, 18) + self.assertEqual(wat1.end_lineno, 5) + self.assertEqual(wat1.col_offset, 14) + self.assertEqual(wat1.end_col_offset, 26) # check the call call = middle.value self.assertEqual(type(call), ast.Call) @@ -427,10 +485,14 @@ def test_ast_line_numbers_with_parentheses(self): self.assertEqual(call.end_col_offset, 31) # check the second wat self.assertEqual(type(wat2), ast.Constant) - self.assertEqual(wat2.lineno, 4) + self.assertEqual(wat2.lineno, 5) self.assertEqual(wat2.end_lineno, 6) - self.assertEqual(wat2.col_offset, 12) - self.assertEqual(wat2.end_col_offset, 18) + self.assertEqual(wat2.col_offset, 32) + # wat ends at the offset 17, but the whole f-string + # ends at the offset 18 (since the quote is part of the + # f-string but not the wat string) + self.assertEqual(wat2.end_col_offset, 17) + self.assertEqual(fstring.end_col_offset, 18) def test_docstring(self): def f(): @@ -467,7 +529,7 @@ def test_literal(self): self.assertEqual(f' ', ' ') def test_unterminated_string(self): - self.assertAllRaise(SyntaxError, 'f-string: unterminated string', + self.assertAllRaise(SyntaxError, 'unterminated string', [r"""f'{"x'""", r"""f'{"x}'""", r"""f'{("x'""", @@ -475,28 +537,33 @@ def test_unterminated_string(self): ]) def test_mismatched_parens(self): - self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\}' " + self.assertAllRaise(SyntaxError, r"closing parenthesis '\}' " r"does not match opening parenthesis '\('", ["f'{((}'", ]) - self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\)' " + self.assertAllRaise(SyntaxError, r"closing parenthesis '\)' " r"does not match opening parenthesis '\['", ["f'{a[4)}'", ]) - self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\]' " + self.assertAllRaise(SyntaxError, r"closing parenthesis '\]' " r"does not match opening parenthesis '\('", ["f'{a(4]}'", ]) - self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\}' " + self.assertAllRaise(SyntaxError, r"closing parenthesis '\}' " r"does not match opening parenthesis '\['", ["f'{a[4}'", ]) - self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\}' " + self.assertAllRaise(SyntaxError, r"closing parenthesis '\}' " r"does not match opening parenthesis '\('", ["f'{a(4}'", ]) self.assertRaises(SyntaxError, eval, "f'{" + "("*500 + "}'") + def test_fstring_nested_too_deeply(self): + self.assertAllRaise(SyntaxError, + "f-string: expressions nested too deeply", + ['f"{1+2:{1+2:{1+1:{1}}}}"']) + def test_double_braces(self): self.assertEqual(f'{{', '{') self.assertEqual(f'a{{', 'a{') @@ -559,8 +626,14 @@ def test_compile_time_concat(self): self.assertEqual(f'' '' f'', '') self.assertEqual(f'' '' f'' '', '') - self.assertAllRaise(SyntaxError, "f-string: expecting '}'", - ["f'{3' f'}'", # can't concat to get a valid f-string + # This is not really [f'{'] + [f'}'] since we treat the inside + # of braces as a purely new context, so it is actually f'{ and + # then eval(' f') (a valid expression) and then }' which would + # constitute a valid f-string. + self.assertEqual(f'{' f'}', ' f') + + self.assertAllRaise(SyntaxError, "expecting '}'", + ['''f'{3' f"}"''', # can't concat to get a valid f-string ]) def test_comments(self): @@ -618,25 +691,19 @@ def test_format_specifier_expressions(self): self.assertEqual(f'{-10:-{"#"}1{0}x}', ' -0xa') self.assertEqual(f'{-10:{"-"}#{1}0{"x"}}', ' -0xa') self.assertEqual(f'{10:#{3 != {4:5} and width}x}', ' 0xa') + self.assertEqual(f'result: {value:{width:{0}}.{precision:1}}', 'result: 12.35') - self.assertAllRaise(SyntaxError, - """f-string: invalid conversion character 'r{"': """ - """expected 's', 'r', or 'a'""", + self.assertAllRaise(SyntaxError, "f-string: expecting ':' or '}'", ["""f'{"s"!r{":10"}}'""", - # This looks like a nested format spec. ]) - self.assertAllRaise(SyntaxError, "f-string: invalid syntax", + self.assertAllRaise(SyntaxError, + "f-string: expecting a valid expression after '{'", [# Invalid syntax inside a nested spec. "f'{4:{/5}}'", ]) - self.assertAllRaise(SyntaxError, "f-string: expressions nested too deeply", - [# Can't nest format specifiers. - "f'result: {value:{width:{0}}.{precision:1}}'", - ]) - self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character', [# No expansion inside conversion or for # the : or ! itself. @@ -655,7 +722,8 @@ def __format__(self, spec): self.assertEqual(f'{x} {x}', '1 2') def test_missing_expression(self): - self.assertAllRaise(SyntaxError, 'f-string: empty expression not allowed', + self.assertAllRaise(SyntaxError, + "f-string: valid expression required before '}'", ["f'{}'", "f'{ }'" "f' {} '", @@ -667,8 +735,8 @@ def test_missing_expression(self): "f'''{\t\f\r\n}'''", ]) - # Different error messages are raised when a specifier ('!', ':' or '=') is used after an empty expression - self.assertAllRaise(SyntaxError, "f-string: expression required before '!'", + self.assertAllRaise(SyntaxError, + "f-string: valid expression required before '!'", ["f'{!r}'", "f'{ !r}'", "f'{!}'", @@ -689,7 +757,8 @@ def test_missing_expression(self): "f'{ !xr:a}'", ]) - self.assertAllRaise(SyntaxError, "f-string: expression required before ':'", + self.assertAllRaise(SyntaxError, + "f-string: valid expression required before ':'", ["f'{:}'", "f'{ :!}'", "f'{:2}'", @@ -697,7 +766,8 @@ def test_missing_expression(self): "f'{:'", ]) - self.assertAllRaise(SyntaxError, "f-string: expression required before '='", + self.assertAllRaise(SyntaxError, + "f-string: valid expression required before '='", ["f'{=}'", "f'{ =}'", "f'{ =:}'", @@ -715,24 +785,18 @@ def test_missing_expression(self): def test_parens_in_expressions(self): self.assertEqual(f'{3,}', '(3,)') - # Add these because when an expression is evaluated, parens - # are added around it. But we shouldn't go from an invalid - # expression to a valid one. The added parens are just - # supposed to allow whitespace (including newlines). - self.assertAllRaise(SyntaxError, 'f-string: invalid syntax', + self.assertAllRaise(SyntaxError, + "f-string: expecting a valid expression after '{'", ["f'{,}'", - "f'{,}'", # this is (,), which is an error ]) self.assertAllRaise(SyntaxError, r"f-string: unmatched '\)'", ["f'{3)+(4}'", ]) - self.assertAllRaise(SyntaxError, 'unterminated string literal', - ["f'{\n}'", - ]) def test_newlines_before_syntax_error(self): - self.assertAllRaise(SyntaxError, "invalid syntax", + self.assertAllRaise(SyntaxError, + "f-string: expecting a valid expression after '{'", ["f'{.}'", "\nf'{.}'", "\n\nf'{.}'"]) def test_backslashes_in_string_part(self): @@ -776,7 +840,7 @@ def test_backslashes_in_string_part(self): self.assertEqual(f'2\x203', '2 3') self.assertEqual(f'\x203', ' 3') - with self.assertWarns(SyntaxWarning): # invalid escape sequence + with self.assertWarns(DeprecationWarning): # invalid escape sequence value = eval(r"f'\{6*7}'") self.assertEqual(value, '\\42') self.assertEqual(f'\\{6*7}', '\\42') @@ -809,18 +873,40 @@ def test_misformed_unicode_character_name(self): r"'\N{GREEK CAPITAL LETTER DELTA'", ]) - def test_no_backslashes_in_expression_part(self): - self.assertAllRaise(SyntaxError, 'f-string expression part cannot include a backslash', - [r"f'{\'a\'}'", - r"f'{\t3}'", - r"f'{\}'", - r"rf'{\'a\'}'", - r"rf'{\t3}'", - r"rf'{\}'", - r"""rf'{"\N{LEFT CURLY BRACKET}"}'""", - r"f'{\n}'", + def test_backslashes_in_expression_part(self): + self.assertEqual(f"{( + 1 + + 2 + )}", "3") + + self.assertEqual("\N{LEFT CURLY BRACKET}", '{') + self.assertEqual(f'{"\N{LEFT CURLY BRACKET}"}', '{') + self.assertEqual(rf'{"\N{LEFT CURLY BRACKET}"}', '{') + + self.assertAllRaise(SyntaxError, + "f-string: valid expression required before '}'", + ["f'{\n}'", ]) + def test_invalid_backslashes_inside_fstring_context(self): + # All of these variations are invalid python syntax, + # so they are also invalid in f-strings as well. + cases = [ + formatting.format(expr=expr) + for formatting in [ + "{expr}", + "f'{{{expr}}}'", + "rf'{{{expr}}}'", + ] + for expr in [ + r"\'a\'", + r"\t3", + r"\\"[0], + ] + ] + self.assertAllRaise(SyntaxError, 'unexpected character after line continuation', + cases) + def test_no_escapes_for_braces(self): """ Only literal curly braces begin an expression. @@ -843,11 +929,69 @@ def test_lambda(self): self.assertEqual(f'{(lambda y:x*y)("8"):10}', "88888 ") # lambda doesn't work without parens, because the colon - # makes the parser think it's a format_spec - self.assertAllRaise(SyntaxError, 'f-string: invalid syntax', + # makes the parser think it's a format_spec + # emit warning if we can match a format_spec + self.assertAllRaise(SyntaxError, + "f-string: lambda expressions are not allowed " + "without parentheses", ["f'{lambda x:x}'", + "f'{lambda :x}'", + "f'{lambda *arg, :x}'", + "f'{1, lambda:x}'", + ]) + + # but don't emit the paren warning in general cases + self.assertAllRaise(SyntaxError, + "f-string: expecting a valid expression after '{'", + ["f'{lambda x:}'", + "f'{lambda :}'", + "f'{+ lambda:None}'", ]) + def test_valid_prefixes(self): + self.assertEqual(F'{1}', "1") + self.assertEqual(FR'{2}', "2") + self.assertEqual(fR'{3}', "3") + + def test_roundtrip_raw_quotes(self): + self.assertEqual(fr"\'", "\\'") + self.assertEqual(fr'\"', '\\"') + self.assertEqual(fr'\"\'', '\\"\\\'') + self.assertEqual(fr'\'\"', '\\\'\\"') + self.assertEqual(fr'\"\'\"', '\\"\\\'\\"') + self.assertEqual(fr'\'\"\'', '\\\'\\"\\\'') + self.assertEqual(fr'\"\'\"\'', '\\"\\\'\\"\\\'') + + def test_fstring_backslash_before_double_bracket(self): + self.assertEqual(f'\{{\}}', '\\{\\}') + self.assertEqual(f'\{{', '\\{') + self.assertEqual(f'\{{{1+1}', '\\{2') + self.assertEqual(f'\}}{1+1}', '\\}2') + self.assertEqual(f'{1+1}\}}', '2\\}') + self.assertEqual(fr'\{{\}}', '\\{\\}') + self.assertEqual(fr'\{{', '\\{') + self.assertEqual(fr'\{{{1+1}', '\\{2') + self.assertEqual(fr'\}}{1+1}', '\\}2') + self.assertEqual(fr'{1+1}\}}', '2\\}') + + def test_fstring_backslash_prefix_raw(self): + self.assertEqual(f'\\', '\\') + self.assertEqual(f'\\\\', '\\\\') + self.assertEqual(fr'\\', r'\\') + self.assertEqual(fr'\\\\', r'\\\\') + self.assertEqual(rf'\\', r'\\') + self.assertEqual(rf'\\\\', r'\\\\') + self.assertEqual(Rf'\\', R'\\') + self.assertEqual(Rf'\\\\', R'\\\\') + self.assertEqual(fR'\\', R'\\') + self.assertEqual(fR'\\\\', R'\\\\') + self.assertEqual(FR'\\', R'\\') + self.assertEqual(FR'\\\\', R'\\\\') + + def test_fstring_format_spec_greedy_matching(self): + self.assertEqual(f"{1:}}}", "1}") + self.assertEqual(f"{1:>3{5}}}}", " 1}") + def test_yield(self): # Not terribly useful, but make sure the yield turns # a function into a generator @@ -1037,6 +1181,11 @@ def test_conversions(self): self.assertEqual(f'{"a"!r}', "'a'") self.assertEqual(f'{"a"!a}', "'a'") + # Conversions can have trailing whitespace after them since it + # does not provide any significance + self.assertEqual(f"{3!s }", "3") + self.assertEqual(f'{3.14!s :10.10}', '3.14 ') + # Not a conversion. self.assertEqual(f'{"a!r"}', "a!r") @@ -1049,16 +1198,27 @@ def test_conversions(self): "f'{3!g'", ]) - self.assertAllRaise(SyntaxError, 'f-string: missed conversion character', + self.assertAllRaise(SyntaxError, 'f-string: missing conversion character', ["f'{3!}'", "f'{3!:'", "f'{3!:}'", ]) - for conv in 'g', 'A', '3', 'G', '!', ' s', 's ', ' s ', '?', '?', '?': + for conv_identifier in 'g', 'A', 'G', '?', '?': self.assertAllRaise(SyntaxError, "f-string: invalid conversion character %r: " - "expected 's', 'r', or 'a'" % conv, + "expected 's', 'r', or 'a'" % conv_identifier, + ["f'{3!" + conv_identifier + "}'"]) + + for conv_non_identifier in '3', '!': + self.assertAllRaise(SyntaxError, + "f-string: invalid conversion character", + ["f'{3!" + conv_non_identifier + "}'"]) + + for conv in ' s', ' s ': + self.assertAllRaise(SyntaxError, + "f-string: conversion type must come right after the" + " exclamanation mark", ["f'{3!" + conv + "}'"]) self.assertAllRaise(SyntaxError, @@ -1097,8 +1257,7 @@ def test_mismatched_braces(self): ]) self.assertAllRaise(SyntaxError, "f-string: expecting '}'", - ["f'{3:{{>10}'", - "f'{3'", + ["f'{3'", "f'{3!'", "f'{3:'", "f'{3!s'", @@ -1111,11 +1270,14 @@ def test_mismatched_braces(self): "f'{{{'", "f'{{}}{'", "f'{'", - "f'x{<'", # See bpo-46762. - "f'x{>'", "f'{i='", # See gh-93418. ]) + self.assertAllRaise(SyntaxError, + "f-string: expecting a valid expression after '{'", + ["f'{3:{{>10}'", + ]) + # But these are just normal strings. self.assertEqual(f'{"{"}', '{') self.assertEqual(f'{"}"}', '}') @@ -1314,6 +1476,7 @@ def __repr__(self): self.assertEqual(f'X{x =}Y', 'Xx ='+repr(x)+'Y') self.assertEqual(f'X{x= }Y', 'Xx= '+repr(x)+'Y') self.assertEqual(f'X{x = }Y', 'Xx = '+repr(x)+'Y') + self.assertEqual(f"sadsd {1 + 1 = :{1 + 1:1d}f}", "sadsd 1 + 1 = 2.000000") # These next lines contains tabs. Backslash escapes don't # work in f-strings. @@ -1335,7 +1498,8 @@ def test_walrus(self): self.assertEqual(x, 10) def test_invalid_syntax_error_message(self): - with self.assertRaisesRegex(SyntaxError, "f-string: invalid syntax"): + with self.assertRaisesRegex(SyntaxError, + "f-string: expecting '=', or '!', or ':', or '}'"): compile("f'{a $ b}'", "?", "exec") def test_with_two_commas_in_format_specifier(self): @@ -1359,12 +1523,11 @@ def test_with_an_underscore_and_a_comma_in_format_specifier(self): f'{1:_,}' def test_syntax_error_for_starred_expressions(self): - error_msg = re.escape("cannot use starred expression here") - with self.assertRaisesRegex(SyntaxError, error_msg): + with self.assertRaisesRegex(SyntaxError, "can't use starred expression here"): compile("f'{*a}'", "?", "exec") - error_msg = re.escape("cannot use double starred expression here") - with self.assertRaisesRegex(SyntaxError, error_msg): + with self.assertRaisesRegex(SyntaxError, + "f-string: expecting a valid expression after '{'"): compile("f'{**a}'", "?", "exec") if __name__ == '__main__': diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 63c2501cfe23..283a7c23609e 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1625,6 +1625,10 @@ def test_random_files(self): # 7 more testfiles fail. Remove them also until the failure is diagnosed. testfiles.remove(os.path.join(tempdir, "test_unicode_identifiers.py")) + + # TODO: Remove this once we can unparse PEP 701 syntax + testfiles.remove(os.path.join(tempdir, "test_fstring.py")) + for f in ('buffer', 'builtin', 'fileio', 'inspect', 'os', 'platform', 'sys'): testfiles.remove(os.path.join(tempdir, "test_%s.py") % f) @@ -1937,25 +1941,39 @@ def test_string(self): """) self.check_tokenize('f"abc"', """\ - STRING 'f"abc"' (1, 0) (1, 6) + FSTRING_START 'f"' (1, 0) (1, 2) + FSTRING_MIDDLE 'abc' (1, 2) (1, 5) + FSTRING_END '"' (1, 5) (1, 6) """) self.check_tokenize('fR"a{b}c"', """\ - STRING 'fR"a{b}c"' (1, 0) (1, 9) + FSTRING_START 'fR"' (1, 0) (1, 3) + FSTRING_MIDDLE 'a' (1, 3) (1, 4) + LBRACE '{' (1, 4) (1, 5) + NAME 'b' (1, 5) (1, 6) + RBRACE '}' (1, 6) (1, 7) + FSTRING_MIDDLE 'c' (1, 7) (1, 8) + FSTRING_END '"' (1, 8) (1, 9) """) self.check_tokenize('f"""abc"""', """\ - STRING 'f\"\"\"abc\"\"\"' (1, 0) (1, 10) + FSTRING_START 'f\"""' (1, 0) (1, 4) + FSTRING_MIDDLE 'abc' (1, 4) (1, 7) + FSTRING_END '\"""' (1, 7) (1, 10) """) self.check_tokenize(r'f"abc\ def"', """\ - STRING 'f"abc\\\\\\ndef"' (1, 0) (2, 4) + FSTRING_START \'f"\' (1, 0) (1, 2) + FSTRING_MIDDLE 'abc\\\\\\ndef' (1, 2) (2, 3) + FSTRING_END '"' (2, 3) (2, 4) """) self.check_tokenize(r'Rf"abc\ def"', """\ - STRING 'Rf"abc\\\\\\ndef"' (1, 0) (2, 4) + FSTRING_START 'Rf"' (1, 0) (1, 3) + FSTRING_MIDDLE 'abc\\\\\\ndef' (1, 3) (2, 3) + FSTRING_END '"' (2, 3) (2, 4) """) def test_function(self): diff --git a/Lib/test/test_type_comments.py b/Lib/test/test_type_comments.py index 8db7394d1512..aba4a44be9da 100644 --- a/Lib/test/test_type_comments.py +++ b/Lib/test/test_type_comments.py @@ -272,7 +272,7 @@ def test_matmul(self): pass def test_fstring(self): - for tree in self.parse_all(fstring, minver=6): + for tree in self.parse_all(fstring): pass def test_underscorednumber(self): diff --git a/Lib/token.py b/Lib/token.py index 95b107c6643b..1459d12b376f 100644 --- a/Lib/token.py +++ b/Lib/token.py @@ -57,18 +57,22 @@ RARROW = 51 ELLIPSIS = 52 COLONEQUAL = 53 -OP = 54 -AWAIT = 55 -ASYNC = 56 -TYPE_IGNORE = 57 -TYPE_COMMENT = 58 -SOFT_KEYWORD = 59 +EXCLAMATION = 54 +OP = 55 +AWAIT = 56 +ASYNC = 57 +TYPE_IGNORE = 58 +TYPE_COMMENT = 59 +SOFT_KEYWORD = 60 +FSTRING_START = 61 +FSTRING_MIDDLE = 62 +FSTRING_END = 63 # These aren't used by the C tokenizer but are needed for tokenize.py -ERRORTOKEN = 60 -COMMENT = 61 -NL = 62 -ENCODING = 63 -N_TOKENS = 64 +ERRORTOKEN = 64 +COMMENT = 65 +NL = 66 +ENCODING = 67 +N_TOKENS = 68 # Special definitions for cooperation with parser NT_OFFSET = 256 @@ -78,6 +82,7 @@ __all__.extend(tok_name.values()) EXACT_TOKEN_TYPES = { + '!': EXCLAMATION, '!=': NOTEQUAL, '%': PERCENT, '%=': PERCENTEQUAL, diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-17-16-00-32.gh-issue-102856.UunJ7y.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-17-16-00-32.gh-issue-102856.UunJ7y.rst new file mode 100644 index 000000000000..35eceb83816b --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-17-16-00-32.gh-issue-102856.UunJ7y.rst @@ -0,0 +1 @@ +Implement the required C tokenizer changes for PEP 701. Patch by Pablo Galindo Salgado, Lysandros Nikolaou, Batuhan Taskaya, Marta G?mez Mac?as and sunmy2019. diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index 46390966892d..55c0f6fdd620 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -1,6 +1,7 @@ #include #include "pegen.h" +#include "tokenizer.h" #include "string_parser.h" #include "pycore_runtime.h" // _PyRuntime @@ -853,96 +854,6 @@ _PyPegen_seq_delete_starred_exprs(Parser *p, asdl_seq *kwargs) return new_seq; } -expr_ty -_PyPegen_concatenate_strings(Parser *p, asdl_seq *strings) -{ - Py_ssize_t len = asdl_seq_LEN(strings); - assert(len > 0); - - Token *first = asdl_seq_GET_UNTYPED(strings, 0); - Token *last = asdl_seq_GET_UNTYPED(strings, len - 1); - - int bytesmode = 0; - PyObject *bytes_str = NULL; - - FstringParser state; - _PyPegen_FstringParser_Init(&state); - - for (Py_ssize_t i = 0; i < len; i++) { - Token *t = asdl_seq_GET_UNTYPED(strings, i); - - int this_bytesmode; - int this_rawmode; - PyObject *s; - const char *fstr; - Py_ssize_t fstrlen = -1; - - if (_PyPegen_parsestr(p, &this_bytesmode, &this_rawmode, &s, &fstr, &fstrlen, t) != 0) { - goto error; - } - - /* Check that we are not mixing bytes with unicode. */ - if (i != 0 && bytesmode != this_bytesmode) { - RAISE_SYNTAX_ERROR("cannot mix bytes and nonbytes literals"); - Py_XDECREF(s); - goto error; - } - bytesmode = this_bytesmode; - - if (fstr != NULL) { - assert(s == NULL && !bytesmode); - - int result = _PyPegen_FstringParser_ConcatFstring(p, &state, &fstr, fstr + fstrlen, - this_rawmode, 0, first, t, last); - if (result < 0) { - goto error; - } - } - else { - /* String or byte string. */ - assert(s != NULL && fstr == NULL); - assert(bytesmode ? PyBytes_CheckExact(s) : PyUnicode_CheckExact(s)); - - if (bytesmode) { - if (i == 0) { - bytes_str = s; - } - else { - PyBytes_ConcatAndDel(&bytes_str, s); - if (!bytes_str) { - goto error; - } - } - } - else { - /* This is a regular string. Concatenate it. */ - if (_PyPegen_FstringParser_ConcatAndDel(&state, s) < 0) { - goto error; - } - } - } - } - - if (bytesmode) { - if (_PyArena_AddPyObject(p->arena, bytes_str) < 0) { - goto error; - } - return _PyAST_Constant(bytes_str, NULL, first->lineno, - first->col_offset, last->end_lineno, - last->end_col_offset, p->arena); - } - - return _PyPegen_FstringParser_Finish(p, &state, first, last); - -error: - Py_XDECREF(bytes_str); - _PyPegen_FstringParser_Dealloc(&state); - if (PyErr_Occurred()) { - _Pypegen_raise_decode_error(p); - } - return NULL; -} - expr_ty _PyPegen_ensure_imaginary(Parser *p, expr_ty exp) { @@ -1054,6 +965,18 @@ _PyPegen_check_legacy_stmt(Parser *p, expr_ty name) { return 0; } +expr_ty +_PyPegen_check_fstring_conversion(Parser *p, Token* symbol, expr_ty conv) { + if (symbol->lineno != conv->lineno || symbol->end_col_offset != conv->col_offset) { + return RAISE_SYNTAX_ERROR_KNOWN_RANGE( + symbol, conv, + "f-string: conversion type must come right after the exclamanation mark" + ); + } + return conv; +} + + const char * _PyPegen_get_expr_name(expr_ty e) { @@ -1271,3 +1194,439 @@ _PyPegen_nonparen_genexp_in_call(Parser *p, expr_ty args, asdl_comprehension_seq "Generator expression must be parenthesized" ); } + +// Fstring stuff + +static expr_ty +decode_fstring_buffer(Parser *p, int lineno, int col_offset, int end_lineno, + int end_col_offset) +{ + tokenizer_mode *tok_mode = &(p->tok->tok_mode_stack[p->tok->tok_mode_stack_index]); + assert(tok_mode->last_expr_buffer != NULL); + assert(tok_mode->last_expr_size >= 0 && tok_mode->last_expr_end >= 0); + + PyObject *res = PyUnicode_DecodeUTF8( + tok_mode->last_expr_buffer, + tok_mode->last_expr_size - tok_mode->last_expr_end, + NULL + ); + if (!res || _PyArena_AddPyObject(p->arena, res) < 0) { + Py_XDECREF(res); + return NULL; + } + + return _PyAST_Constant(res, NULL, lineno, col_offset, end_lineno, end_col_offset, p->arena); +} + +static expr_ty +_PyPegen_decode_fstring_part(Parser* p, int is_raw, expr_ty constant) { + assert(PyUnicode_CheckExact(constant->v.Constant.value)); + + const char* bstr = PyUnicode_AsUTF8(constant->v.Constant.value); + if (bstr == NULL) { + return NULL; + } + + size_t len; + if (strcmp(bstr, "{{") == 0 || strcmp(bstr, "}}") == 0) { + len = 1; + } else { + len = strlen(bstr); + } + + is_raw = is_raw || strchr(bstr, '\\') == NULL; + PyObject *str = _PyPegen_decode_string(p, is_raw, bstr, len, NULL); + if (str == NULL) { + _Pypegen_raise_decode_error(p); + return NULL; + } + if (_PyArena_AddPyObject(p->arena, str) < 0) { + Py_DECREF(str); + return NULL; + } + return _PyAST_Constant(str, NULL, constant->lineno, constant->col_offset, + constant->end_lineno, constant->end_col_offset, + p->arena); +} + +static asdl_expr_seq * +unpack_top_level_joined_strs(Parser *p, asdl_expr_seq *raw_expressions) +{ + /* The parser might put multiple f-string values into an individual + * JoinedStr node at the top level due to stuff like f-string debugging + * expressions. This function flattens those and promotes them to the + * upper level. Only simplifies AST, but the compiler already takes care + * of the regular output, so this is not necessary if you are not going + * to expose the output AST to Python level. */ + + Py_ssize_t i, req_size, raw_size; + + req_size = raw_size = asdl_seq_LEN(raw_expressions); + expr_ty expr; + for (i = 0; i < raw_size; i++) { + expr = asdl_seq_GET(raw_expressions, i); + if (expr->kind == JoinedStr_kind) { + req_size += asdl_seq_LEN(expr->v.JoinedStr.values) - 1; + } + } + + asdl_expr_seq *expressions = _Py_asdl_expr_seq_new(req_size, p->arena); + + Py_ssize_t raw_index, req_index = 0; + for (raw_index = 0; raw_index < raw_size; raw_index++) { + expr = asdl_seq_GET(raw_expressions, raw_index); + if (expr->kind == JoinedStr_kind) { + asdl_expr_seq *values = expr->v.JoinedStr.values; + for (Py_ssize_t n = 0; n < asdl_seq_LEN(values); n++) { + asdl_seq_SET(expressions, req_index, asdl_seq_GET(values, n)); + req_index++; + } + } else { + asdl_seq_SET(expressions, req_index, expr); + req_index++; + } + } + return expressions; +} + +expr_ty +_PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b) { + asdl_expr_seq *expr = unpack_top_level_joined_strs(p, raw_expressions); + Py_ssize_t n_items = asdl_seq_LEN(expr); + + const char* quote_str = PyBytes_AsString(a->bytes); + if (quote_str == NULL) { + return NULL; + } + int is_raw = strpbrk(quote_str, "rR") != NULL; + + asdl_expr_seq *seq = _Py_asdl_expr_seq_new(n_items, p->arena); + if (seq == NULL) { + return NULL; + } + + Py_ssize_t index = 0; + for (Py_ssize_t i = 0; i < n_items; i++) { + expr_ty item = asdl_seq_GET(expr, i); + if (item->kind == Constant_kind) { + item = _PyPegen_decode_fstring_part(p, is_raw, item); + if (item == NULL) { + return NULL; + } + + /* Tokenizer emits string parts even when the underlying string + might become an empty value (e.g. FSTRING_MIDDLE with the value \\n) + so we need to check for them and simplify it here. */ + if (PyUnicode_CheckExact(item->v.Constant.value) + && PyUnicode_GET_LENGTH(item->v.Constant.value) == 0) { + continue; + } + } + asdl_seq_SET(seq, index++, item); + } + + asdl_expr_seq *resized_exprs; + if (index != n_items) { + resized_exprs = _Py_asdl_expr_seq_new(index, p->arena); + if (resized_exprs == NULL) { + return NULL; + } + for (Py_ssize_t i = 0; i < index; i++) { + asdl_seq_SET(resized_exprs, i, asdl_seq_GET(seq, i)); + } + } + else { + resized_exprs = seq; + } + + return _PyAST_JoinedStr(resized_exprs, a->lineno, a->col_offset, + b->end_lineno, b->end_col_offset, + p->arena); +} + +expr_ty _PyPegen_constant_from_token(Parser* p, Token* tok) { + char* bstr = PyBytes_AsString(tok->bytes); + if (bstr == NULL) { + return NULL; + } + PyObject* str = PyUnicode_FromString(bstr); + if (str == NULL) { + return NULL; + } + if (_PyArena_AddPyObject(p->arena, str) < 0) { + Py_DECREF(str); + return NULL; + } + return _PyAST_Constant(str, NULL, tok->lineno, tok->col_offset, + tok->end_lineno, tok->end_col_offset, + p->arena); +} + +expr_ty _PyPegen_constant_from_string(Parser* p, Token* tok) { + char* the_str = PyBytes_AsString(tok->bytes); + if (the_str == NULL) { + return NULL; + } + PyObject *s = _PyPegen_parse_string(p, tok); + if (s == NULL) { + _Pypegen_raise_decode_error(p); + return NULL; + } + if (_PyArena_AddPyObject(p->arena, s) < 0) { + Py_DECREF(s); + return NULL; + } + PyObject *kind = NULL; + if (the_str && the_str[0] == 'u') { + kind = _PyPegen_new_identifier(p, "u"); + if (kind == NULL) { + return NULL; + } + } + return _PyAST_Constant(s, kind, tok->lineno, tok->col_offset, tok->end_lineno, tok->end_col_offset, p->arena); +} + +expr_ty _PyPegen_formatted_value(Parser *p, expr_ty expression, Token *debug, expr_ty conversion, + expr_ty format, int lineno, int col_offset, int end_lineno, int end_col_offset, + PyArena *arena) { + int conversion_val = -1; + if (conversion != NULL) { + assert(conversion->kind == Name_kind); + Py_UCS4 first = PyUnicode_READ_CHAR(conversion->v.Name.id, 0); + + if (PyUnicode_GET_LENGTH(conversion->v.Name.id) > 1 || + !(first == 's' || first == 'r' || first == 'a')) { + RAISE_SYNTAX_ERROR_KNOWN_LOCATION(conversion, + "f-string: invalid conversion character %R: expected 's', 'r', or 'a'", + conversion->v.Name.id); + return NULL; + } + + conversion_val = Py_SAFE_DOWNCAST(first, Py_UCS4, int); + } + else if (debug && !format) { + /* If no conversion is specified, use !r for debug expressions */ + conversion_val = (int)'r'; + } + + expr_ty formatted_value = _PyAST_FormattedValue( + expression, conversion_val, format, + lineno, col_offset, end_lineno, + end_col_offset, arena + ); + + if (debug) { + /* Find the non whitespace token after the "=" */ + int debug_end_line, debug_end_offset; + + if (conversion) { + debug_end_line = conversion->lineno; + debug_end_offset = conversion->col_offset; + } + else if (format) { + debug_end_line = format->lineno; + debug_end_offset = format->col_offset + 1; // HACK: ?? + } + else { + debug_end_line = end_lineno; + debug_end_offset = end_col_offset; + } + + expr_ty debug_text = decode_fstring_buffer(p, lineno, col_offset + 1, + debug_end_line, debug_end_offset - 1); + if (!debug_text) { + return NULL; + } + + asdl_expr_seq *values = _Py_asdl_expr_seq_new(2, arena); + asdl_seq_SET(values, 0, debug_text); + asdl_seq_SET(values, 1, formatted_value); + return _PyAST_JoinedStr(values, lineno, col_offset, debug_end_line, debug_end_offset, p->arena); + } + else { + return formatted_value; + } +} + +expr_ty +_PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings, + int lineno, int col_offset, int end_lineno, + int end_col_offset, PyArena *arena) +{ + Py_ssize_t len = asdl_seq_LEN(strings); + assert(len > 0); + + int f_string_found = 0; + int unicode_string_found = 0; + int bytes_found = 0; + + Py_ssize_t i = 0; + Py_ssize_t n_flattened_elements = 0; + for (i = 0; i < len; i++) { + expr_ty elem = asdl_seq_GET(strings, i); + if (elem->kind == Constant_kind) { + if (PyBytes_CheckExact(elem->v.Constant.value)) { + bytes_found = 1; + } else { + unicode_string_found = 1; + } + n_flattened_elements++; + } else { + n_flattened_elements += asdl_seq_LEN(elem->v.JoinedStr.values); + f_string_found = 1; + } + } + + if ((unicode_string_found || f_string_found) && bytes_found) { + RAISE_SYNTAX_ERROR("cannot mix bytes and nonbytes literals"); + return NULL; + } + + if (bytes_found) { + PyObject* res = PyBytes_FromString(""); + + /* Bytes literals never get a kind, but just for consistency + since they are represented as Constant nodes, we'll mirror + the same behavior as unicode strings for determining the + kind. */ + PyObject* kind = asdl_seq_GET(strings, 0)->v.Constant.kind; + for (i = 0; i < len; i++) { + expr_ty elem = asdl_seq_GET(strings, i); + PyBytes_Concat(&res, elem->v.Constant.value); + } + if (!res || _PyArena_AddPyObject(arena, res) < 0) { + Py_XDECREF(res); + return NULL; + } + return _PyAST_Constant(res, kind, lineno, col_offset, end_lineno, end_col_offset, p->arena); + } + + if (!f_string_found && len == 1) { + return asdl_seq_GET(strings, 0); + } + + asdl_expr_seq* flattened = _Py_asdl_expr_seq_new(n_flattened_elements, p->arena); + if (flattened == NULL) { + return NULL; + } + + /* build flattened list */ + Py_ssize_t current_pos = 0; + Py_ssize_t j = 0; + for (i = 0; i < len; i++) { + expr_ty elem = asdl_seq_GET(strings, i); + if (elem->kind == Constant_kind) { + asdl_seq_SET(flattened, current_pos++, elem); + } else { + for (j = 0; j < asdl_seq_LEN(elem->v.JoinedStr.values); j++) { + expr_ty subvalue = asdl_seq_GET(elem->v.JoinedStr.values, j); + if (subvalue == NULL) { + return NULL; + } + asdl_seq_SET(flattened, current_pos++, subvalue); + } + } + } + + /* calculate folded element count */ + Py_ssize_t n_elements = 0; + int prev_is_constant = 0; + for (i = 0; i < n_flattened_elements; i++) { + expr_ty elem = asdl_seq_GET(flattened, i); + + /* The concatenation of a FormattedValue and an empty Contant should + lead to the FormattedValue itself. Thus, we will not take any empty + constants into account, just as in `_PyPegen_joined_str` */ + if (f_string_found && elem->kind == Constant_kind && + PyUnicode_CheckExact(elem->v.Constant.value) && + PyUnicode_GET_LENGTH(elem->v.Constant.value) == 0) + continue; + + if (!prev_is_constant || elem->kind != Constant_kind) { + n_elements++; + } + prev_is_constant = elem->kind == Constant_kind; + } + + asdl_expr_seq* values = _Py_asdl_expr_seq_new(n_elements, p->arena); + if (values == NULL) { + return NULL; + } + + /* build folded list */ + _PyUnicodeWriter writer; + current_pos = 0; + for (i = 0; i < n_flattened_elements; i++) { + expr_ty elem = asdl_seq_GET(flattened, i); + + /* if the current elem and the following are constants, + fold them and all consequent constants */ + if (elem->kind == Constant_kind) { + if (i + 1 < n_flattened_elements && + asdl_seq_GET(flattened, i + 1)->kind == Constant_kind) { + expr_ty first_elem = elem; + + /* When a string is getting concatenated, the kind of the string + is determined by the first string in the concatenation + sequence. + + u"abc" "def" -> u"abcdef" + "abc" u"abc" -> "abcabc" */ + PyObject *kind = elem->v.Constant.kind; + + _PyUnicodeWriter_Init(&writer); + expr_ty last_elem = elem; + for (j = i; j < n_flattened_elements; j++) { + expr_ty current_elem = asdl_seq_GET(flattened, j); + if (current_elem->kind == Constant_kind) { + if (_PyUnicodeWriter_WriteStr( + &writer, current_elem->v.Constant.value)) { + _PyUnicodeWriter_Dealloc(&writer); + return NULL; + } + last_elem = current_elem; + } else { + break; + } + } + i = j - 1; + + PyObject *concat_str = _PyUnicodeWriter_Finish(&writer); + if (concat_str == NULL) { + _PyUnicodeWriter_Dealloc(&writer); + return NULL; + } + if (_PyArena_AddPyObject(p->arena, concat_str) < 0) { + Py_DECREF(concat_str); + return NULL; + } + elem = _PyAST_Constant(concat_str, kind, first_elem->lineno, + first_elem->col_offset, + last_elem->end_lineno, + last_elem->end_col_offset, p->arena); + if (elem == NULL) { + return NULL; + } + } + + /* Drop all empty contanst strings */ + if (f_string_found && + PyUnicode_CheckExact(elem->v.Constant.value) && + PyUnicode_GET_LENGTH(elem->v.Constant.value) == 0) { + continue; + } + } + + asdl_seq_SET(values, current_pos++, elem); + } + + if (!f_string_found) { + assert(n_elements == 1); + expr_ty elem = asdl_seq_GET(values, 0); + assert(elem->kind == Constant_kind); + return elem; + } + + assert(current_pos == n_elements); + return _PyAST_JoinedStr(values, lineno, col_offset, end_lineno, end_col_offset, p->arena); +} diff --git a/Parser/parser.c b/Parser/parser.c index e0a88a9cc72c..771366844fc4 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -17,52 +17,52 @@ static KeywordToken *reserved_keywords[] = { (KeywordToken[]) {{NULL, -1}}, (KeywordToken[]) {{NULL, -1}}, (KeywordToken[]) { - {"if", 641}, - {"as", 639}, - {"in", 650}, + {"if", 642}, + {"as", 640}, + {"in", 651}, {"or", 574}, {"is", 582}, {NULL, -1}, }, (KeywordToken[]) { - {"del", 603}, - {"def", 651}, - {"for", 649}, - {"try", 623}, + {"del", 604}, + {"def", 652}, + {"for", 650}, + {"try", 624}, {"and", 575}, {"not", 581}, {NULL, -1}, }, (KeywordToken[]) { - {"from", 607}, + {"from", 608}, {"pass", 504}, - {"with", 614}, - {"elif", 643}, - {"else", 644}, - {"None", 601}, - {"True", 600}, + {"with", 615}, + {"elif", 644}, + {"else", 645}, + {"None", 602}, + {"True", 601}, {NULL, -1}, }, (KeywordToken[]) { {"raise", 522}, {"yield", 573}, {"break", 508}, - {"class", 653}, - {"while", 646}, - {"False", 602}, + {"class", 654}, + {"while", 647}, + {"False", 603}, {NULL, -1}, }, (KeywordToken[]) { {"return", 519}, - {"import", 606}, + {"import", 607}, {"assert", 526}, {"global", 523}, - {"except", 636}, - {"lambda", 586}, + {"except", 637}, + {"lambda", 600}, {NULL, -1}, }, (KeywordToken[]) { - {"finally", 632}, + {"finally", 633}, {NULL, -1}, }, (KeywordToken[]) { @@ -224,341 +224,370 @@ static char *soft_keywords[] = { #define lambda_param_with_default_type 1144 #define lambda_param_maybe_default_type 1145 #define lambda_param_type 1146 -#define strings_type 1147 -#define list_type 1148 -#define tuple_type 1149 -#define set_type 1150 -#define dict_type 1151 -#define double_starred_kvpairs_type 1152 -#define double_starred_kvpair_type 1153 -#define kvpair_type 1154 -#define for_if_clauses_type 1155 -#define for_if_clause_type 1156 -#define listcomp_type 1157 -#define setcomp_type 1158 -#define genexp_type 1159 -#define dictcomp_type 1160 -#define arguments_type 1161 -#define args_type 1162 -#define kwargs_type 1163 -#define starred_expression_type 1164 -#define kwarg_or_starred_type 1165 -#define kwarg_or_double_starred_type 1166 -#define star_targets_type 1167 -#define star_targets_list_seq_type 1168 -#define star_targets_tuple_seq_type 1169 -#define star_target_type 1170 -#define target_with_star_atom_type 1171 -#define star_atom_type 1172 -#define single_target_type 1173 -#define single_subscript_attribute_target_type 1174 -#define t_primary_type 1175 // Left-recursive -#define t_lookahead_type 1176 -#define del_targets_type 1177 -#define del_target_type 1178 -#define del_t_atom_type 1179 -#define type_expressions_type 1180 -#define func_type_comment_type 1181 -#define invalid_arguments_type 1182 -#define invalid_kwarg_type 1183 -#define expression_without_invalid_type 1184 -#define invalid_legacy_expression_type 1185 -#define invalid_expression_type 1186 -#define invalid_named_expression_type 1187 -#define invalid_assignment_type 1188 -#define invalid_ann_assign_target_type 1189 -#define invalid_del_stmt_type 1190 -#define invalid_block_type 1191 -#define invalid_comprehension_type 1192 -#define invalid_dict_comprehension_type 1193 -#define invalid_parameters_type 1194 -#define invalid_default_type 1195 -#define invalid_star_etc_type 1196 -#define invalid_kwds_type 1197 -#define invalid_parameters_helper_type 1198 -#define invalid_lambda_parameters_type 1199 -#define invalid_lambda_parameters_helper_type 1200 -#define invalid_lambda_star_etc_type 1201 -#define invalid_lambda_kwds_type 1202 -#define invalid_double_type_comments_type 1203 -#define invalid_with_item_type 1204 -#define invalid_for_target_type 1205 -#define invalid_group_type 1206 -#define invalid_import_type 1207 -#define invalid_import_from_targets_type 1208 -#define invalid_with_stmt_type 1209 -#define invalid_with_stmt_indent_type 1210 -#define invalid_try_stmt_type 1211 -#define invalid_except_stmt_type 1212 -#define invalid_finally_stmt_type 1213 -#define invalid_except_stmt_indent_type 1214 -#define invalid_except_star_stmt_indent_type 1215 -#define invalid_match_stmt_type 1216 -#define invalid_case_block_type 1217 -#define invalid_as_pattern_type 1218 -#define invalid_class_pattern_type 1219 -#define invalid_class_argument_pattern_type 1220 -#define invalid_if_stmt_type 1221 -#define invalid_elif_stmt_type 1222 -#define invalid_else_stmt_type 1223 -#define invalid_while_stmt_type 1224 -#define invalid_for_stmt_type 1225 -#define invalid_def_raw_type 1226 -#define invalid_class_def_raw_type 1227 -#define invalid_double_starred_kvpairs_type 1228 -#define invalid_kvpair_type 1229 -#define invalid_starred_expression_type 1230 -#define _loop0_1_type 1231 -#define _loop0_2_type 1232 -#define _loop1_3_type 1233 -#define _loop0_5_type 1234 -#define _gather_4_type 1235 -#define _tmp_6_type 1236 -#define _tmp_7_type 1237 -#define _tmp_8_type 1238 -#define _tmp_9_type 1239 -#define _tmp_10_type 1240 -#define _tmp_11_type 1241 -#define _tmp_12_type 1242 -#define _tmp_13_type 1243 -#define _loop1_14_type 1244 -#define _tmp_15_type 1245 -#define _tmp_16_type 1246 -#define _tmp_17_type 1247 -#define _loop0_19_type 1248 -#define _gather_18_type 1249 -#define _loop0_21_type 1250 -#define _gather_20_type 1251 -#define _tmp_22_type 1252 -#define _tmp_23_type 1253 -#define _loop0_24_type 1254 -#define _loop1_25_type 1255 -#define _loop0_27_type 1256 -#define _gather_26_type 1257 -#define _tmp_28_type 1258 -#define _loop0_30_type 1259 -#define _gather_29_type 1260 -#define _tmp_31_type 1261 -#define _loop1_32_type 1262 -#define _tmp_33_type 1263 -#define _tmp_34_type 1264 -#define _tmp_35_type 1265 -#define _loop0_36_type 1266 -#define _loop0_37_type 1267 -#define _loop0_38_type 1268 -#define _loop1_39_type 1269 -#define _loop0_40_type 1270 -#define _loop1_41_type 1271 -#define _loop1_42_type 1272 -#define _loop1_43_type 1273 -#define _loop0_44_type 1274 -#define _loop1_45_type 1275 -#define _loop0_46_type 1276 -#define _loop1_47_type 1277 -#define _loop0_48_type 1278 -#define _loop0_49_type 1279 -#define _loop1_50_type 1280 -#define _loop0_52_type 1281 -#define _gather_51_type 1282 -#define _loop0_54_type 1283 -#define _gather_53_type 1284 -#define _loop0_56_type 1285 -#define _gather_55_type 1286 -#define _loop0_58_type 1287 -#define _gather_57_type 1288 -#define _tmp_59_type 1289 -#define _loop1_60_type 1290 -#define _loop1_61_type 1291 -#define _tmp_62_type 1292 -#define _tmp_63_type 1293 -#define _loop1_64_type 1294 -#define _loop0_66_type 1295 -#define _gather_65_type 1296 -#define _tmp_67_type 1297 -#define _tmp_68_type 1298 -#define _tmp_69_type 1299 -#define _tmp_70_type 1300 -#define _loop0_72_type 1301 -#define _gather_71_type 1302 -#define _loop0_74_type 1303 -#define _gather_73_type 1304 -#define _tmp_75_type 1305 -#define _loop0_77_type 1306 -#define _gather_76_type 1307 -#define _loop0_79_type 1308 -#define _gather_78_type 1309 -#define _loop1_80_type 1310 -#define _loop1_81_type 1311 -#define _loop0_83_type 1312 -#define _gather_82_type 1313 -#define _loop1_84_type 1314 -#define _loop1_85_type 1315 -#define _loop1_86_type 1316 -#define _tmp_87_type 1317 -#define _loop0_89_type 1318 -#define _gather_88_type 1319 -#define _tmp_90_type 1320 -#define _tmp_91_type 1321 -#define _tmp_92_type 1322 -#define _tmp_93_type 1323 -#define _tmp_94_type 1324 -#define _loop0_95_type 1325 -#define _loop0_96_type 1326 -#define _loop0_97_type 1327 -#define _loop1_98_type 1328 -#define _loop0_99_type 1329 -#define _loop1_100_type 1330 -#define _loop1_101_type 1331 -#define _loop1_102_type 1332 -#define _loop0_103_type 1333 -#define _loop1_104_type 1334 -#define _loop0_105_type 1335 -#define _loop1_106_type 1336 -#define _loop0_107_type 1337 -#define _loop1_108_type 1338 -#define _loop1_109_type 1339 -#define _tmp_110_type 1340 -#define _loop0_112_type 1341 -#define _gather_111_type 1342 -#define _loop1_113_type 1343 -#define _loop0_114_type 1344 -#define _loop0_115_type 1345 -#define _tmp_116_type 1346 -#define _loop0_118_type 1347 -#define _gather_117_type 1348 -#define _tmp_119_type 1349 -#define _loop0_121_type 1350 -#define _gather_120_type 1351 -#define _loop0_123_type 1352 -#define _gather_122_type 1353 -#define _loop0_125_type 1354 -#define _gather_124_type 1355 -#define _loop0_127_type 1356 -#define _gather_126_type 1357 -#define _loop0_128_type 1358 -#define _loop0_130_type 1359 -#define _gather_129_type 1360 -#define _loop1_131_type 1361 -#define _tmp_132_type 1362 -#define _loop0_134_type 1363 -#define _gather_133_type 1364 -#define _loop0_136_type 1365 -#define _gather_135_type 1366 -#define _loop0_138_type 1367 -#define _gather_137_type 1368 -#define _loop0_140_type 1369 -#define _gather_139_type 1370 -#define _loop0_142_type 1371 -#define _gather_141_type 1372 -#define _tmp_143_type 1373 -#define _tmp_144_type 1374 -#define _tmp_145_type 1375 -#define _tmp_146_type 1376 -#define _tmp_147_type 1377 -#define _tmp_148_type 1378 -#define _tmp_149_type 1379 -#define _tmp_150_type 1380 -#define _tmp_151_type 1381 -#define _tmp_152_type 1382 -#define _tmp_153_type 1383 -#define _loop0_154_type 1384 -#define _loop0_155_type 1385 -#define _loop0_156_type 1386 -#define _tmp_157_type 1387 -#define _tmp_158_type 1388 -#define _tmp_159_type 1389 -#define _tmp_160_type 1390 -#define _tmp_161_type 1391 -#define _loop0_162_type 1392 -#define _loop0_163_type 1393 -#define _loop0_164_type 1394 -#define _loop1_165_type 1395 -#define _tmp_166_type 1396 -#define _loop0_167_type 1397 -#define _tmp_168_type 1398 -#define _loop0_169_type 1399 -#define _loop1_170_type 1400 -#define _tmp_171_type 1401 -#define _tmp_172_type 1402 -#define _tmp_173_type 1403 -#define _loop0_174_type 1404 -#define _tmp_175_type 1405 -#define _tmp_176_type 1406 -#define _loop1_177_type 1407 -#define _tmp_178_type 1408 -#define _loop0_179_type 1409 -#define _loop0_180_type 1410 -#define _loop0_181_type 1411 -#define _loop0_183_type 1412 -#define _gather_182_type 1413 -#define _tmp_184_type 1414 -#define _loop0_185_type 1415 -#define _tmp_186_type 1416 -#define _loop0_187_type 1417 -#define _loop1_188_type 1418 -#define _loop1_189_type 1419 -#define _tmp_190_type 1420 -#define _tmp_191_type 1421 -#define _loop0_192_type 1422 -#define _tmp_193_type 1423 -#define _tmp_194_type 1424 -#define _tmp_195_type 1425 -#define _loop0_197_type 1426 -#define _gather_196_type 1427 -#define _loop0_199_type 1428 -#define _gather_198_type 1429 -#define _loop0_201_type 1430 -#define _gather_200_type 1431 -#define _loop0_203_type 1432 -#define _gather_202_type 1433 -#define _tmp_204_type 1434 -#define _loop0_205_type 1435 -#define _loop1_206_type 1436 -#define _tmp_207_type 1437 -#define _loop0_208_type 1438 -#define _loop1_209_type 1439 -#define _tmp_210_type 1440 -#define _tmp_211_type 1441 -#define _tmp_212_type 1442 -#define _tmp_213_type 1443 -#define _tmp_214_type 1444 -#define _tmp_215_type 1445 -#define _tmp_216_type 1446 -#define _tmp_217_type 1447 -#define _tmp_218_type 1448 -#define _tmp_219_type 1449 -#define _loop0_221_type 1450 -#define _gather_220_type 1451 -#define _tmp_222_type 1452 -#define _tmp_223_type 1453 -#define _tmp_224_type 1454 -#define _tmp_225_type 1455 -#define _tmp_226_type 1456 -#define _tmp_227_type 1457 -#define _tmp_228_type 1458 -#define _tmp_229_type 1459 -#define _tmp_230_type 1460 -#define _tmp_231_type 1461 -#define _tmp_232_type 1462 -#define _tmp_233_type 1463 -#define _tmp_234_type 1464 -#define _tmp_235_type 1465 -#define _tmp_236_type 1466 -#define _tmp_237_type 1467 -#define _tmp_238_type 1468 -#define _tmp_239_type 1469 -#define _tmp_240_type 1470 -#define _tmp_241_type 1471 -#define _tmp_242_type 1472 -#define _tmp_243_type 1473 -#define _tmp_244_type 1474 -#define _tmp_245_type 1475 -#define _tmp_246_type 1476 -#define _tmp_247_type 1477 -#define _tmp_248_type 1478 -#define _tmp_249_type 1479 -#define _tmp_250_type 1480 -#define _tmp_251_type 1481 +#define fstring_middle_type 1147 +#define fstring_replacement_field_type 1148 +#define fstring_conversion_type 1149 +#define fstring_full_format_spec_type 1150 +#define fstring_format_spec_type 1151 +#define string_type 1152 +#define strings_type 1153 +#define list_type 1154 +#define tuple_type 1155 +#define set_type 1156 +#define dict_type 1157 +#define double_starred_kvpairs_type 1158 +#define double_starred_kvpair_type 1159 +#define kvpair_type 1160 +#define for_if_clauses_type 1161 +#define for_if_clause_type 1162 +#define listcomp_type 1163 +#define setcomp_type 1164 +#define genexp_type 1165 +#define dictcomp_type 1166 +#define arguments_type 1167 +#define args_type 1168 +#define kwargs_type 1169 +#define starred_expression_type 1170 +#define kwarg_or_starred_type 1171 +#define kwarg_or_double_starred_type 1172 +#define star_targets_type 1173 +#define star_targets_list_seq_type 1174 +#define star_targets_tuple_seq_type 1175 +#define star_target_type 1176 +#define target_with_star_atom_type 1177 +#define star_atom_type 1178 +#define single_target_type 1179 +#define single_subscript_attribute_target_type 1180 +#define t_primary_type 1181 // Left-recursive +#define t_lookahead_type 1182 +#define del_targets_type 1183 +#define del_target_type 1184 +#define del_t_atom_type 1185 +#define type_expressions_type 1186 +#define func_type_comment_type 1187 +#define invalid_arguments_type 1188 +#define invalid_kwarg_type 1189 +#define expression_without_invalid_type 1190 +#define invalid_legacy_expression_type 1191 +#define invalid_expression_type 1192 +#define invalid_named_expression_type 1193 +#define invalid_assignment_type 1194 +#define invalid_ann_assign_target_type 1195 +#define invalid_del_stmt_type 1196 +#define invalid_block_type 1197 +#define invalid_comprehension_type 1198 +#define invalid_dict_comprehension_type 1199 +#define invalid_parameters_type 1200 +#define invalid_default_type 1201 +#define invalid_star_etc_type 1202 +#define invalid_kwds_type 1203 +#define invalid_parameters_helper_type 1204 +#define invalid_lambda_parameters_type 1205 +#define invalid_lambda_parameters_helper_type 1206 +#define invalid_lambda_star_etc_type 1207 +#define invalid_lambda_kwds_type 1208 +#define invalid_double_type_comments_type 1209 +#define invalid_with_item_type 1210 +#define invalid_for_target_type 1211 +#define invalid_group_type 1212 +#define invalid_import_type 1213 +#define invalid_import_from_targets_type 1214 +#define invalid_with_stmt_type 1215 +#define invalid_with_stmt_indent_type 1216 +#define invalid_try_stmt_type 1217 +#define invalid_except_stmt_type 1218 +#define invalid_finally_stmt_type 1219 +#define invalid_except_stmt_indent_type 1220 +#define invalid_except_star_stmt_indent_type 1221 +#define invalid_match_stmt_type 1222 +#define invalid_case_block_type 1223 +#define invalid_as_pattern_type 1224 +#define invalid_class_pattern_type 1225 +#define invalid_class_argument_pattern_type 1226 +#define invalid_if_stmt_type 1227 +#define invalid_elif_stmt_type 1228 +#define invalid_else_stmt_type 1229 +#define invalid_while_stmt_type 1230 +#define invalid_for_stmt_type 1231 +#define invalid_def_raw_type 1232 +#define invalid_class_def_raw_type 1233 +#define invalid_double_starred_kvpairs_type 1234 +#define invalid_kvpair_type 1235 +#define invalid_starred_expression_type 1236 +#define invalid_replacement_field_type 1237 +#define invalid_conversion_character_type 1238 +#define _loop0_1_type 1239 +#define _loop0_2_type 1240 +#define _loop0_3_type 1241 +#define _loop1_4_type 1242 +#define _loop0_6_type 1243 +#define _gather_5_type 1244 +#define _tmp_7_type 1245 +#define _tmp_8_type 1246 +#define _tmp_9_type 1247 +#define _tmp_10_type 1248 +#define _tmp_11_type 1249 +#define _tmp_12_type 1250 +#define _tmp_13_type 1251 +#define _tmp_14_type 1252 +#define _loop1_15_type 1253 +#define _tmp_16_type 1254 +#define _tmp_17_type 1255 +#define _tmp_18_type 1256 +#define _loop0_20_type 1257 +#define _gather_19_type 1258 +#define _loop0_22_type 1259 +#define _gather_21_type 1260 +#define _tmp_23_type 1261 +#define _tmp_24_type 1262 +#define _loop0_25_type 1263 +#define _loop1_26_type 1264 +#define _loop0_28_type 1265 +#define _gather_27_type 1266 +#define _tmp_29_type 1267 +#define _loop0_31_type 1268 +#define _gather_30_type 1269 +#define _tmp_32_type 1270 +#define _loop1_33_type 1271 +#define _tmp_34_type 1272 +#define _tmp_35_type 1273 +#define _tmp_36_type 1274 +#define _loop0_37_type 1275 +#define _loop0_38_type 1276 +#define _loop0_39_type 1277 +#define _loop1_40_type 1278 +#define _loop0_41_type 1279 +#define _loop1_42_type 1280 +#define _loop1_43_type 1281 +#define _loop1_44_type 1282 +#define _loop0_45_type 1283 +#define _loop1_46_type 1284 +#define _loop0_47_type 1285 +#define _loop1_48_type 1286 +#define _loop0_49_type 1287 +#define _loop0_50_type 1288 +#define _loop1_51_type 1289 +#define _loop0_53_type 1290 +#define _gather_52_type 1291 +#define _loop0_55_type 1292 +#define _gather_54_type 1293 +#define _loop0_57_type 1294 +#define _gather_56_type 1295 +#define _loop0_59_type 1296 +#define _gather_58_type 1297 +#define _tmp_60_type 1298 +#define _loop1_61_type 1299 +#define _loop1_62_type 1300 +#define _tmp_63_type 1301 +#define _tmp_64_type 1302 +#define _loop1_65_type 1303 +#define _loop0_67_type 1304 +#define _gather_66_type 1305 +#define _tmp_68_type 1306 +#define _tmp_69_type 1307 +#define _tmp_70_type 1308 +#define _tmp_71_type 1309 +#define _loop0_73_type 1310 +#define _gather_72_type 1311 +#define _loop0_75_type 1312 +#define _gather_74_type 1313 +#define _tmp_76_type 1314 +#define _loop0_78_type 1315 +#define _gather_77_type 1316 +#define _loop0_80_type 1317 +#define _gather_79_type 1318 +#define _loop1_81_type 1319 +#define _loop1_82_type 1320 +#define _loop0_84_type 1321 +#define _gather_83_type 1322 +#define _loop1_85_type 1323 +#define _loop1_86_type 1324 +#define _loop1_87_type 1325 +#define _tmp_88_type 1326 +#define _loop0_90_type 1327 +#define _gather_89_type 1328 +#define _tmp_91_type 1329 +#define _tmp_92_type 1330 +#define _tmp_93_type 1331 +#define _tmp_94_type 1332 +#define _tmp_95_type 1333 +#define _tmp_96_type 1334 +#define _loop0_97_type 1335 +#define _loop0_98_type 1336 +#define _loop0_99_type 1337 +#define _loop1_100_type 1338 +#define _loop0_101_type 1339 +#define _loop1_102_type 1340 +#define _loop1_103_type 1341 +#define _loop1_104_type 1342 +#define _loop0_105_type 1343 +#define _loop1_106_type 1344 +#define _loop0_107_type 1345 +#define _loop1_108_type 1346 +#define _loop0_109_type 1347 +#define _loop1_110_type 1348 +#define _tmp_111_type 1349 +#define _loop0_112_type 1350 +#define _loop1_113_type 1351 +#define _tmp_114_type 1352 +#define _loop0_116_type 1353 +#define _gather_115_type 1354 +#define _loop1_117_type 1355 +#define _loop0_118_type 1356 +#define _loop0_119_type 1357 +#define _tmp_120_type 1358 +#define _loop0_122_type 1359 +#define _gather_121_type 1360 +#define _tmp_123_type 1361 +#define _loop0_125_type 1362 +#define _gather_124_type 1363 +#define _loop0_127_type 1364 +#define _gather_126_type 1365 +#define _loop0_129_type 1366 +#define _gather_128_type 1367 +#define _loop0_131_type 1368 +#define _gather_130_type 1369 +#define _loop0_132_type 1370 +#define _loop0_134_type 1371 +#define _gather_133_type 1372 +#define _loop1_135_type 1373 +#define _tmp_136_type 1374 +#define _loop0_138_type 1375 +#define _gather_137_type 1376 +#define _loop0_140_type 1377 +#define _gather_139_type 1378 +#define _loop0_142_type 1379 +#define _gather_141_type 1380 +#define _loop0_144_type 1381 +#define _gather_143_type 1382 +#define _loop0_146_type 1383 +#define _gather_145_type 1384 +#define _tmp_147_type 1385 +#define _tmp_148_type 1386 +#define _tmp_149_type 1387 +#define _tmp_150_type 1388 +#define _tmp_151_type 1389 +#define _tmp_152_type 1390 +#define _tmp_153_type 1391 +#define _tmp_154_type 1392 +#define _tmp_155_type 1393 +#define _tmp_156_type 1394 +#define _tmp_157_type 1395 +#define _tmp_158_type 1396 +#define _loop0_159_type 1397 +#define _loop0_160_type 1398 +#define _loop0_161_type 1399 +#define _tmp_162_type 1400 +#define _tmp_163_type 1401 +#define _tmp_164_type 1402 +#define _tmp_165_type 1403 +#define _tmp_166_type 1404 +#define _loop0_167_type 1405 +#define _loop0_168_type 1406 +#define _loop0_169_type 1407 +#define _loop1_170_type 1408 +#define _tmp_171_type 1409 +#define _loop0_172_type 1410 +#define _tmp_173_type 1411 +#define _loop0_174_type 1412 +#define _loop1_175_type 1413 +#define _tmp_176_type 1414 +#define _tmp_177_type 1415 +#define _tmp_178_type 1416 +#define _loop0_179_type 1417 +#define _tmp_180_type 1418 +#define _tmp_181_type 1419 +#define _loop1_182_type 1420 +#define _tmp_183_type 1421 +#define _loop0_184_type 1422 +#define _loop0_185_type 1423 +#define _loop0_186_type 1424 +#define _loop0_188_type 1425 +#define _gather_187_type 1426 +#define _tmp_189_type 1427 +#define _loop0_190_type 1428 +#define _tmp_191_type 1429 +#define _loop0_192_type 1430 +#define _loop1_193_type 1431 +#define _loop1_194_type 1432 +#define _tmp_195_type 1433 +#define _tmp_196_type 1434 +#define _loop0_197_type 1435 +#define _tmp_198_type 1436 +#define _tmp_199_type 1437 +#define _tmp_200_type 1438 +#define _loop0_202_type 1439 +#define _gather_201_type 1440 +#define _loop0_204_type 1441 +#define _gather_203_type 1442 +#define _loop0_206_type 1443 +#define _gather_205_type 1444 +#define _loop0_208_type 1445 +#define _gather_207_type 1446 +#define _tmp_209_type 1447 +#define _loop0_210_type 1448 +#define _loop1_211_type 1449 +#define _tmp_212_type 1450 +#define _loop0_213_type 1451 +#define _loop1_214_type 1452 +#define _tmp_215_type 1453 +#define _tmp_216_type 1454 +#define _tmp_217_type 1455 +#define _tmp_218_type 1456 +#define _tmp_219_type 1457 +#define _tmp_220_type 1458 +#define _tmp_221_type 1459 +#define _tmp_222_type 1460 +#define _tmp_223_type 1461 +#define _tmp_224_type 1462 +#define _loop0_226_type 1463 +#define _gather_225_type 1464 +#define _tmp_227_type 1465 +#define _tmp_228_type 1466 +#define _tmp_229_type 1467 +#define _tmp_230_type 1468 +#define _tmp_231_type 1469 +#define _tmp_232_type 1470 +#define _tmp_233_type 1471 +#define _tmp_234_type 1472 +#define _tmp_235_type 1473 +#define _tmp_236_type 1474 +#define _tmp_237_type 1475 +#define _tmp_238_type 1476 +#define _tmp_239_type 1477 +#define _loop0_240_type 1478 +#define _tmp_241_type 1479 +#define _tmp_242_type 1480 +#define _tmp_243_type 1481 +#define _tmp_244_type 1482 +#define _tmp_245_type 1483 +#define _tmp_246_type 1484 +#define _tmp_247_type 1485 +#define _tmp_248_type 1486 +#define _tmp_249_type 1487 +#define _tmp_250_type 1488 +#define _tmp_251_type 1489 +#define _tmp_252_type 1490 +#define _tmp_253_type 1491 +#define _tmp_254_type 1492 +#define _tmp_255_type 1493 +#define _tmp_256_type 1494 +#define _tmp_257_type 1495 +#define _tmp_258_type 1496 +#define _tmp_259_type 1497 +#define _tmp_260_type 1498 +#define _tmp_261_type 1499 +#define _tmp_262_type 1500 +#define _tmp_263_type 1501 +#define _tmp_264_type 1502 +#define _tmp_265_type 1503 +#define _tmp_266_type 1504 +#define _tmp_267_type 1505 +#define _tmp_268_type 1506 +#define _tmp_269_type 1507 +#define _tmp_270_type 1508 +#define _tmp_271_type 1509 +#define _tmp_272_type 1510 static mod_ty file_rule(Parser *p); static mod_ty interactive_rule(Parser *p); @@ -707,6 +736,12 @@ static arg_ty lambda_param_no_default_rule(Parser *p); static NameDefaultPair* lambda_param_with_default_rule(Parser *p); static NameDefaultPair* lambda_param_maybe_default_rule(Parser *p); static arg_ty lambda_param_rule(Parser *p); +static expr_ty fstring_middle_rule(Parser *p); +static expr_ty fstring_replacement_field_rule(Parser *p); +static expr_ty fstring_conversion_rule(Parser *p); +static expr_ty fstring_full_format_spec_rule(Parser *p); +static expr_ty fstring_format_spec_rule(Parser *p); +static expr_ty string_rule(Parser *p); static expr_ty strings_rule(Parser *p); static expr_ty list_rule(Parser *p); static expr_ty tuple_rule(Parser *p); @@ -791,12 +826,14 @@ static void *invalid_class_def_raw_rule(Parser *p); static void *invalid_double_starred_kvpairs_rule(Parser *p); static void *invalid_kvpair_rule(Parser *p); static void *invalid_starred_expression_rule(Parser *p); +static void *invalid_replacement_field_rule(Parser *p); +static void *invalid_conversion_character_rule(Parser *p); static asdl_seq *_loop0_1_rule(Parser *p); static asdl_seq *_loop0_2_rule(Parser *p); -static asdl_seq *_loop1_3_rule(Parser *p); -static asdl_seq *_loop0_5_rule(Parser *p); -static asdl_seq *_gather_4_rule(Parser *p); -static void *_tmp_6_rule(Parser *p); +static asdl_seq *_loop0_3_rule(Parser *p); +static asdl_seq *_loop1_4_rule(Parser *p); +static asdl_seq *_loop0_6_rule(Parser *p); +static asdl_seq *_gather_5_rule(Parser *p); static void *_tmp_7_rule(Parser *p); static void *_tmp_8_rule(Parser *p); static void *_tmp_9_rule(Parser *p); @@ -804,139 +841,139 @@ static void *_tmp_10_rule(Parser *p); static void *_tmp_11_rule(Parser *p); static void *_tmp_12_rule(Parser *p); static void *_tmp_13_rule(Parser *p); -static asdl_seq *_loop1_14_rule(Parser *p); -static void *_tmp_15_rule(Parser *p); +static void *_tmp_14_rule(Parser *p); +static asdl_seq *_loop1_15_rule(Parser *p); static void *_tmp_16_rule(Parser *p); static void *_tmp_17_rule(Parser *p); -static asdl_seq *_loop0_19_rule(Parser *p); -static asdl_seq *_gather_18_rule(Parser *p); -static asdl_seq *_loop0_21_rule(Parser *p); -static asdl_seq *_gather_20_rule(Parser *p); -static void *_tmp_22_rule(Parser *p); +static void *_tmp_18_rule(Parser *p); +static asdl_seq *_loop0_20_rule(Parser *p); +static asdl_seq *_gather_19_rule(Parser *p); +static asdl_seq *_loop0_22_rule(Parser *p); +static asdl_seq *_gather_21_rule(Parser *p); static void *_tmp_23_rule(Parser *p); -static asdl_seq *_loop0_24_rule(Parser *p); -static asdl_seq *_loop1_25_rule(Parser *p); -static asdl_seq *_loop0_27_rule(Parser *p); -static asdl_seq *_gather_26_rule(Parser *p); -static void *_tmp_28_rule(Parser *p); -static asdl_seq *_loop0_30_rule(Parser *p); -static asdl_seq *_gather_29_rule(Parser *p); -static void *_tmp_31_rule(Parser *p); -static asdl_seq *_loop1_32_rule(Parser *p); -static void *_tmp_33_rule(Parser *p); +static void *_tmp_24_rule(Parser *p); +static asdl_seq *_loop0_25_rule(Parser *p); +static asdl_seq *_loop1_26_rule(Parser *p); +static asdl_seq *_loop0_28_rule(Parser *p); +static asdl_seq *_gather_27_rule(Parser *p); +static void *_tmp_29_rule(Parser *p); +static asdl_seq *_loop0_31_rule(Parser *p); +static asdl_seq *_gather_30_rule(Parser *p); +static void *_tmp_32_rule(Parser *p); +static asdl_seq *_loop1_33_rule(Parser *p); static void *_tmp_34_rule(Parser *p); static void *_tmp_35_rule(Parser *p); -static asdl_seq *_loop0_36_rule(Parser *p); +static void *_tmp_36_rule(Parser *p); static asdl_seq *_loop0_37_rule(Parser *p); static asdl_seq *_loop0_38_rule(Parser *p); -static asdl_seq *_loop1_39_rule(Parser *p); -static asdl_seq *_loop0_40_rule(Parser *p); -static asdl_seq *_loop1_41_rule(Parser *p); +static asdl_seq *_loop0_39_rule(Parser *p); +static asdl_seq *_loop1_40_rule(Parser *p); +static asdl_seq *_loop0_41_rule(Parser *p); static asdl_seq *_loop1_42_rule(Parser *p); static asdl_seq *_loop1_43_rule(Parser *p); -static asdl_seq *_loop0_44_rule(Parser *p); -static asdl_seq *_loop1_45_rule(Parser *p); -static asdl_seq *_loop0_46_rule(Parser *p); -static asdl_seq *_loop1_47_rule(Parser *p); -static asdl_seq *_loop0_48_rule(Parser *p); +static asdl_seq *_loop1_44_rule(Parser *p); +static asdl_seq *_loop0_45_rule(Parser *p); +static asdl_seq *_loop1_46_rule(Parser *p); +static asdl_seq *_loop0_47_rule(Parser *p); +static asdl_seq *_loop1_48_rule(Parser *p); static asdl_seq *_loop0_49_rule(Parser *p); -static asdl_seq *_loop1_50_rule(Parser *p); -static asdl_seq *_loop0_52_rule(Parser *p); -static asdl_seq *_gather_51_rule(Parser *p); -static asdl_seq *_loop0_54_rule(Parser *p); -static asdl_seq *_gather_53_rule(Parser *p); -static asdl_seq *_loop0_56_rule(Parser *p); -static asdl_seq *_gather_55_rule(Parser *p); -static asdl_seq *_loop0_58_rule(Parser *p); -static asdl_seq *_gather_57_rule(Parser *p); -static void *_tmp_59_rule(Parser *p); -static asdl_seq *_loop1_60_rule(Parser *p); +static asdl_seq *_loop0_50_rule(Parser *p); +static asdl_seq *_loop1_51_rule(Parser *p); +static asdl_seq *_loop0_53_rule(Parser *p); +static asdl_seq *_gather_52_rule(Parser *p); +static asdl_seq *_loop0_55_rule(Parser *p); +static asdl_seq *_gather_54_rule(Parser *p); +static asdl_seq *_loop0_57_rule(Parser *p); +static asdl_seq *_gather_56_rule(Parser *p); +static asdl_seq *_loop0_59_rule(Parser *p); +static asdl_seq *_gather_58_rule(Parser *p); +static void *_tmp_60_rule(Parser *p); static asdl_seq *_loop1_61_rule(Parser *p); -static void *_tmp_62_rule(Parser *p); +static asdl_seq *_loop1_62_rule(Parser *p); static void *_tmp_63_rule(Parser *p); -static asdl_seq *_loop1_64_rule(Parser *p); -static asdl_seq *_loop0_66_rule(Parser *p); -static asdl_seq *_gather_65_rule(Parser *p); -static void *_tmp_67_rule(Parser *p); +static void *_tmp_64_rule(Parser *p); +static asdl_seq *_loop1_65_rule(Parser *p); +static asdl_seq *_loop0_67_rule(Parser *p); +static asdl_seq *_gather_66_rule(Parser *p); static void *_tmp_68_rule(Parser *p); static void *_tmp_69_rule(Parser *p); static void *_tmp_70_rule(Parser *p); -static asdl_seq *_loop0_72_rule(Parser *p); -static asdl_seq *_gather_71_rule(Parser *p); -static asdl_seq *_loop0_74_rule(Parser *p); -static asdl_seq *_gather_73_rule(Parser *p); -static void *_tmp_75_rule(Parser *p); -static asdl_seq *_loop0_77_rule(Parser *p); -static asdl_seq *_gather_76_rule(Parser *p); -static asdl_seq *_loop0_79_rule(Parser *p); -static asdl_seq *_gather_78_rule(Parser *p); -static asdl_seq *_loop1_80_rule(Parser *p); +static void *_tmp_71_rule(Parser *p); +static asdl_seq *_loop0_73_rule(Parser *p); +static asdl_seq *_gather_72_rule(Parser *p); +static asdl_seq *_loop0_75_rule(Parser *p); +static asdl_seq *_gather_74_rule(Parser *p); +static void *_tmp_76_rule(Parser *p); +static asdl_seq *_loop0_78_rule(Parser *p); +static asdl_seq *_gather_77_rule(Parser *p); +static asdl_seq *_loop0_80_rule(Parser *p); +static asdl_seq *_gather_79_rule(Parser *p); static asdl_seq *_loop1_81_rule(Parser *p); -static asdl_seq *_loop0_83_rule(Parser *p); -static asdl_seq *_gather_82_rule(Parser *p); -static asdl_seq *_loop1_84_rule(Parser *p); +static asdl_seq *_loop1_82_rule(Parser *p); +static asdl_seq *_loop0_84_rule(Parser *p); +static asdl_seq *_gather_83_rule(Parser *p); static asdl_seq *_loop1_85_rule(Parser *p); static asdl_seq *_loop1_86_rule(Parser *p); -static void *_tmp_87_rule(Parser *p); -static asdl_seq *_loop0_89_rule(Parser *p); -static asdl_seq *_gather_88_rule(Parser *p); -static void *_tmp_90_rule(Parser *p); +static asdl_seq *_loop1_87_rule(Parser *p); +static void *_tmp_88_rule(Parser *p); +static asdl_seq *_loop0_90_rule(Parser *p); +static asdl_seq *_gather_89_rule(Parser *p); static void *_tmp_91_rule(Parser *p); static void *_tmp_92_rule(Parser *p); static void *_tmp_93_rule(Parser *p); static void *_tmp_94_rule(Parser *p); -static asdl_seq *_loop0_95_rule(Parser *p); -static asdl_seq *_loop0_96_rule(Parser *p); +static void *_tmp_95_rule(Parser *p); +static void *_tmp_96_rule(Parser *p); static asdl_seq *_loop0_97_rule(Parser *p); -static asdl_seq *_loop1_98_rule(Parser *p); +static asdl_seq *_loop0_98_rule(Parser *p); static asdl_seq *_loop0_99_rule(Parser *p); static asdl_seq *_loop1_100_rule(Parser *p); -static asdl_seq *_loop1_101_rule(Parser *p); +static asdl_seq *_loop0_101_rule(Parser *p); static asdl_seq *_loop1_102_rule(Parser *p); -static asdl_seq *_loop0_103_rule(Parser *p); +static asdl_seq *_loop1_103_rule(Parser *p); static asdl_seq *_loop1_104_rule(Parser *p); static asdl_seq *_loop0_105_rule(Parser *p); static asdl_seq *_loop1_106_rule(Parser *p); static asdl_seq *_loop0_107_rule(Parser *p); static asdl_seq *_loop1_108_rule(Parser *p); -static asdl_seq *_loop1_109_rule(Parser *p); -static void *_tmp_110_rule(Parser *p); +static asdl_seq *_loop0_109_rule(Parser *p); +static asdl_seq *_loop1_110_rule(Parser *p); +static void *_tmp_111_rule(Parser *p); static asdl_seq *_loop0_112_rule(Parser *p); -static asdl_seq *_gather_111_rule(Parser *p); static asdl_seq *_loop1_113_rule(Parser *p); -static asdl_seq *_loop0_114_rule(Parser *p); -static asdl_seq *_loop0_115_rule(Parser *p); -static void *_tmp_116_rule(Parser *p); +static void *_tmp_114_rule(Parser *p); +static asdl_seq *_loop0_116_rule(Parser *p); +static asdl_seq *_gather_115_rule(Parser *p); +static asdl_seq *_loop1_117_rule(Parser *p); static asdl_seq *_loop0_118_rule(Parser *p); -static asdl_seq *_gather_117_rule(Parser *p); -static void *_tmp_119_rule(Parser *p); -static asdl_seq *_loop0_121_rule(Parser *p); -static asdl_seq *_gather_120_rule(Parser *p); -static asdl_seq *_loop0_123_rule(Parser *p); -static asdl_seq *_gather_122_rule(Parser *p); +static asdl_seq *_loop0_119_rule(Parser *p); +static void *_tmp_120_rule(Parser *p); +static asdl_seq *_loop0_122_rule(Parser *p); +static asdl_seq *_gather_121_rule(Parser *p); +static void *_tmp_123_rule(Parser *p); static asdl_seq *_loop0_125_rule(Parser *p); static asdl_seq *_gather_124_rule(Parser *p); static asdl_seq *_loop0_127_rule(Parser *p); static asdl_seq *_gather_126_rule(Parser *p); -static asdl_seq *_loop0_128_rule(Parser *p); -static asdl_seq *_loop0_130_rule(Parser *p); -static asdl_seq *_gather_129_rule(Parser *p); -static asdl_seq *_loop1_131_rule(Parser *p); -static void *_tmp_132_rule(Parser *p); +static asdl_seq *_loop0_129_rule(Parser *p); +static asdl_seq *_gather_128_rule(Parser *p); +static asdl_seq *_loop0_131_rule(Parser *p); +static asdl_seq *_gather_130_rule(Parser *p); +static asdl_seq *_loop0_132_rule(Parser *p); static asdl_seq *_loop0_134_rule(Parser *p); static asdl_seq *_gather_133_rule(Parser *p); -static asdl_seq *_loop0_136_rule(Parser *p); -static asdl_seq *_gather_135_rule(Parser *p); +static asdl_seq *_loop1_135_rule(Parser *p); +static void *_tmp_136_rule(Parser *p); static asdl_seq *_loop0_138_rule(Parser *p); static asdl_seq *_gather_137_rule(Parser *p); static asdl_seq *_loop0_140_rule(Parser *p); static asdl_seq *_gather_139_rule(Parser *p); static asdl_seq *_loop0_142_rule(Parser *p); static asdl_seq *_gather_141_rule(Parser *p); -static void *_tmp_143_rule(Parser *p); -static void *_tmp_144_rule(Parser *p); -static void *_tmp_145_rule(Parser *p); -static void *_tmp_146_rule(Parser *p); +static asdl_seq *_loop0_144_rule(Parser *p); +static asdl_seq *_gather_143_rule(Parser *p); +static asdl_seq *_loop0_146_rule(Parser *p); +static asdl_seq *_gather_145_rule(Parser *p); static void *_tmp_147_rule(Parser *p); static void *_tmp_148_rule(Parser *p); static void *_tmp_149_rule(Parser *p); @@ -944,79 +981,79 @@ static void *_tmp_150_rule(Parser *p); static void *_tmp_151_rule(Parser *p); static void *_tmp_152_rule(Parser *p); static void *_tmp_153_rule(Parser *p); -static asdl_seq *_loop0_154_rule(Parser *p); -static asdl_seq *_loop0_155_rule(Parser *p); -static asdl_seq *_loop0_156_rule(Parser *p); +static void *_tmp_154_rule(Parser *p); +static void *_tmp_155_rule(Parser *p); +static void *_tmp_156_rule(Parser *p); static void *_tmp_157_rule(Parser *p); static void *_tmp_158_rule(Parser *p); -static void *_tmp_159_rule(Parser *p); -static void *_tmp_160_rule(Parser *p); -static void *_tmp_161_rule(Parser *p); -static asdl_seq *_loop0_162_rule(Parser *p); -static asdl_seq *_loop0_163_rule(Parser *p); -static asdl_seq *_loop0_164_rule(Parser *p); -static asdl_seq *_loop1_165_rule(Parser *p); +static asdl_seq *_loop0_159_rule(Parser *p); +static asdl_seq *_loop0_160_rule(Parser *p); +static asdl_seq *_loop0_161_rule(Parser *p); +static void *_tmp_162_rule(Parser *p); +static void *_tmp_163_rule(Parser *p); +static void *_tmp_164_rule(Parser *p); +static void *_tmp_165_rule(Parser *p); static void *_tmp_166_rule(Parser *p); static asdl_seq *_loop0_167_rule(Parser *p); -static void *_tmp_168_rule(Parser *p); +static asdl_seq *_loop0_168_rule(Parser *p); static asdl_seq *_loop0_169_rule(Parser *p); static asdl_seq *_loop1_170_rule(Parser *p); static void *_tmp_171_rule(Parser *p); -static void *_tmp_172_rule(Parser *p); +static asdl_seq *_loop0_172_rule(Parser *p); static void *_tmp_173_rule(Parser *p); static asdl_seq *_loop0_174_rule(Parser *p); -static void *_tmp_175_rule(Parser *p); +static asdl_seq *_loop1_175_rule(Parser *p); static void *_tmp_176_rule(Parser *p); -static asdl_seq *_loop1_177_rule(Parser *p); +static void *_tmp_177_rule(Parser *p); static void *_tmp_178_rule(Parser *p); static asdl_seq *_loop0_179_rule(Parser *p); -static asdl_seq *_loop0_180_rule(Parser *p); -static asdl_seq *_loop0_181_rule(Parser *p); -static asdl_seq *_loop0_183_rule(Parser *p); -static asdl_seq *_gather_182_rule(Parser *p); -static void *_tmp_184_rule(Parser *p); +static void *_tmp_180_rule(Parser *p); +static void *_tmp_181_rule(Parser *p); +static asdl_seq *_loop1_182_rule(Parser *p); +static void *_tmp_183_rule(Parser *p); +static asdl_seq *_loop0_184_rule(Parser *p); static asdl_seq *_loop0_185_rule(Parser *p); -static void *_tmp_186_rule(Parser *p); -static asdl_seq *_loop0_187_rule(Parser *p); -static asdl_seq *_loop1_188_rule(Parser *p); -static asdl_seq *_loop1_189_rule(Parser *p); -static void *_tmp_190_rule(Parser *p); +static asdl_seq *_loop0_186_rule(Parser *p); +static asdl_seq *_loop0_188_rule(Parser *p); +static asdl_seq *_gather_187_rule(Parser *p); +static void *_tmp_189_rule(Parser *p); +static asdl_seq *_loop0_190_rule(Parser *p); static void *_tmp_191_rule(Parser *p); static asdl_seq *_loop0_192_rule(Parser *p); -static void *_tmp_193_rule(Parser *p); -static void *_tmp_194_rule(Parser *p); +static asdl_seq *_loop1_193_rule(Parser *p); +static asdl_seq *_loop1_194_rule(Parser *p); static void *_tmp_195_rule(Parser *p); +static void *_tmp_196_rule(Parser *p); static asdl_seq *_loop0_197_rule(Parser *p); -static asdl_seq *_gather_196_rule(Parser *p); -static asdl_seq *_loop0_199_rule(Parser *p); -static asdl_seq *_gather_198_rule(Parser *p); -static asdl_seq *_loop0_201_rule(Parser *p); -static asdl_seq *_gather_200_rule(Parser *p); -static asdl_seq *_loop0_203_rule(Parser *p); -static asdl_seq *_gather_202_rule(Parser *p); -static void *_tmp_204_rule(Parser *p); -static asdl_seq *_loop0_205_rule(Parser *p); -static asdl_seq *_loop1_206_rule(Parser *p); -static void *_tmp_207_rule(Parser *p); +static void *_tmp_198_rule(Parser *p); +static void *_tmp_199_rule(Parser *p); +static void *_tmp_200_rule(Parser *p); +static asdl_seq *_loop0_202_rule(Parser *p); +static asdl_seq *_gather_201_rule(Parser *p); +static asdl_seq *_loop0_204_rule(Parser *p); +static asdl_seq *_gather_203_rule(Parser *p); +static asdl_seq *_loop0_206_rule(Parser *p); +static asdl_seq *_gather_205_rule(Parser *p); static asdl_seq *_loop0_208_rule(Parser *p); -static asdl_seq *_loop1_209_rule(Parser *p); -static void *_tmp_210_rule(Parser *p); -static void *_tmp_211_rule(Parser *p); +static asdl_seq *_gather_207_rule(Parser *p); +static void *_tmp_209_rule(Parser *p); +static asdl_seq *_loop0_210_rule(Parser *p); +static asdl_seq *_loop1_211_rule(Parser *p); static void *_tmp_212_rule(Parser *p); -static void *_tmp_213_rule(Parser *p); -static void *_tmp_214_rule(Parser *p); +static asdl_seq *_loop0_213_rule(Parser *p); +static asdl_seq *_loop1_214_rule(Parser *p); static void *_tmp_215_rule(Parser *p); static void *_tmp_216_rule(Parser *p); static void *_tmp_217_rule(Parser *p); static void *_tmp_218_rule(Parser *p); static void *_tmp_219_rule(Parser *p); -static asdl_seq *_loop0_221_rule(Parser *p); -static asdl_seq *_gather_220_rule(Parser *p); +static void *_tmp_220_rule(Parser *p); +static void *_tmp_221_rule(Parser *p); static void *_tmp_222_rule(Parser *p); static void *_tmp_223_rule(Parser *p); static void *_tmp_224_rule(Parser *p); -static void *_tmp_225_rule(Parser *p); -static void *_tmp_226_rule(Parser *p); +static asdl_seq *_loop0_226_rule(Parser *p); +static asdl_seq *_gather_225_rule(Parser *p); static void *_tmp_227_rule(Parser *p); static void *_tmp_228_rule(Parser *p); static void *_tmp_229_rule(Parser *p); @@ -1030,7 +1067,7 @@ static void *_tmp_236_rule(Parser *p); static void *_tmp_237_rule(Parser *p); static void *_tmp_238_rule(Parser *p); static void *_tmp_239_rule(Parser *p); -static void *_tmp_240_rule(Parser *p); +static asdl_seq *_loop0_240_rule(Parser *p); static void *_tmp_241_rule(Parser *p); static void *_tmp_242_rule(Parser *p); static void *_tmp_243_rule(Parser *p); @@ -1042,6 +1079,27 @@ static void *_tmp_248_rule(Parser *p); static void *_tmp_249_rule(Parser *p); static void *_tmp_250_rule(Parser *p); static void *_tmp_251_rule(Parser *p); +static void *_tmp_252_rule(Parser *p); +static void *_tmp_253_rule(Parser *p); +static void *_tmp_254_rule(Parser *p); +static void *_tmp_255_rule(Parser *p); +static void *_tmp_256_rule(Parser *p); +static void *_tmp_257_rule(Parser *p); +static void *_tmp_258_rule(Parser *p); +static void *_tmp_259_rule(Parser *p); +static void *_tmp_260_rule(Parser *p); +static void *_tmp_261_rule(Parser *p); +static void *_tmp_262_rule(Parser *p); +static void *_tmp_263_rule(Parser *p); +static void *_tmp_264_rule(Parser *p); +static void *_tmp_265_rule(Parser *p); +static void *_tmp_266_rule(Parser *p); +static void *_tmp_267_rule(Parser *p); +static void *_tmp_268_rule(Parser *p); +static void *_tmp_269_rule(Parser *p); +static void *_tmp_270_rule(Parser *p); +static void *_tmp_271_rule(Parser *p); +static void *_tmp_272_rule(Parser *p); // file: statements? $ @@ -1247,7 +1305,7 @@ func_type_rule(Parser *p) return _res; } -// fstring: star_expressions +// fstring: FSTRING_START fstring_middle* FSTRING_END static expr_ty fstring_rule(Parser *p) { @@ -1261,24 +1319,35 @@ fstring_rule(Parser *p) } expr_ty _res = NULL; int _mark = p->mark; - { // star_expressions + { // FSTRING_START fstring_middle* FSTRING_END if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> fstring[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); - expr_ty star_expressions_var; + D(fprintf(stderr, "%*c> fstring[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_START fstring_middle* FSTRING_END")); + Token * a; + asdl_seq * b; + Token * c; if ( - (star_expressions_var = star_expressions_rule(p)) // star_expressions + (a = _PyPegen_expect_token(p, FSTRING_START)) // token='FSTRING_START' + && + (b = _loop0_3_rule(p)) // fstring_middle* + && + (c = _PyPegen_expect_token(p, FSTRING_END)) // token='FSTRING_END' ) { - D(fprintf(stderr, "%*c+ fstring[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); - _res = star_expressions_var; + D(fprintf(stderr, "%*c+ fstring[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_START fstring_middle* FSTRING_END")); + _res = _PyPegen_joined_str ( p , a , ( asdl_expr_seq* ) b , c ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s fstring[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_START fstring_middle* FSTRING_END")); } _res = NULL; done: @@ -1308,7 +1377,7 @@ statements_rule(Parser *p) D(fprintf(stderr, "%*c> statements[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "statement+")); asdl_seq * a; if ( - (a = _loop1_3_rule(p)) // statement+ + (a = _loop1_4_rule(p)) // statement+ ) { D(fprintf(stderr, "%*c+ statements[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "statement+")); @@ -1584,7 +1653,7 @@ simple_stmts_rule(Parser *p) asdl_stmt_seq* a; Token * newline_var; if ( - (a = (asdl_stmt_seq*)_gather_4_rule(p)) // ';'.simple_stmt+ + (a = (asdl_stmt_seq*)_gather_5_rule(p)) // ';'.simple_stmt+ && (_opt_var = _PyPegen_expect_token(p, 13), !p->error_indicator) // ';'? && @@ -1731,7 +1800,7 @@ simple_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> simple_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&('import' | 'from') import_stmt")); stmt_ty import_stmt_var; if ( - _PyPegen_lookahead(1, _tmp_6_rule, p) + _PyPegen_lookahead(1, _tmp_7_rule, p) && (import_stmt_var = import_stmt_rule(p)) // import_stmt ) @@ -1806,7 +1875,7 @@ simple_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> simple_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'del' del_stmt")); stmt_ty del_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 603) // token='del' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 604) // token='del' && (del_stmt_var = del_stmt_rule(p)) // del_stmt ) @@ -2006,7 +2075,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&('def' | '@' | ASYNC) function_def")); stmt_ty function_def_var; if ( - _PyPegen_lookahead(1, _tmp_7_rule, p) + _PyPegen_lookahead(1, _tmp_8_rule, p) && (function_def_var = function_def_rule(p)) // function_def ) @@ -2027,7 +2096,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'if' if_stmt")); stmt_ty if_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 641) // token='if' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 642) // token='if' && (if_stmt_var = if_stmt_rule(p)) // if_stmt ) @@ -2048,7 +2117,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&('class' | '@') class_def")); stmt_ty class_def_var; if ( - _PyPegen_lookahead(1, _tmp_8_rule, p) + _PyPegen_lookahead(1, _tmp_9_rule, p) && (class_def_var = class_def_rule(p)) // class_def ) @@ -2069,7 +2138,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&('with' | ASYNC) with_stmt")); stmt_ty with_stmt_var; if ( - _PyPegen_lookahead(1, _tmp_9_rule, p) + _PyPegen_lookahead(1, _tmp_10_rule, p) && (with_stmt_var = with_stmt_rule(p)) // with_stmt ) @@ -2090,7 +2159,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&('for' | ASYNC) for_stmt")); stmt_ty for_stmt_var; if ( - _PyPegen_lookahead(1, _tmp_10_rule, p) + _PyPegen_lookahead(1, _tmp_11_rule, p) && (for_stmt_var = for_stmt_rule(p)) // for_stmt ) @@ -2111,7 +2180,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'try' try_stmt")); stmt_ty try_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 623) // token='try' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 624) // token='try' && (try_stmt_var = try_stmt_rule(p)) // try_stmt ) @@ -2132,7 +2201,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'while' while_stmt")); stmt_ty while_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 646) // token='while' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 647) // token='while' && (while_stmt_var = while_stmt_rule(p)) // while_stmt ) @@ -2215,7 +2284,7 @@ assignment_rule(Parser *p) && (b = expression_rule(p)) // expression && - (c = _tmp_11_rule(p), !p->error_indicator) // ['=' annotated_rhs] + (c = _tmp_12_rule(p), !p->error_indicator) // ['=' annotated_rhs] ) { D(fprintf(stderr, "%*c+ assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME ':' expression ['=' annotated_rhs]")); @@ -2251,13 +2320,13 @@ assignment_rule(Parser *p) expr_ty b; void *c; if ( - (a = _tmp_12_rule(p)) // '(' single_target ')' | single_subscript_attribute_target + (a = _tmp_13_rule(p)) // '(' single_target ')' | single_subscript_attribute_target && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && (b = expression_rule(p)) // expression && - (c = _tmp_13_rule(p), !p->error_indicator) // ['=' annotated_rhs] + (c = _tmp_14_rule(p), !p->error_indicator) // ['=' annotated_rhs] ) { D(fprintf(stderr, "%*c+ assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "('(' single_target ')' | single_subscript_attribute_target) ':' expression ['=' annotated_rhs]")); @@ -2292,9 +2361,9 @@ assignment_rule(Parser *p) void *b; void *tc; if ( - (a = (asdl_expr_seq*)_loop1_14_rule(p)) // ((star_targets '='))+ + (a = (asdl_expr_seq*)_loop1_15_rule(p)) // ((star_targets '='))+ && - (b = _tmp_15_rule(p)) // yield_expr | star_expressions + (b = _tmp_16_rule(p)) // yield_expr | star_expressions && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' && @@ -2340,7 +2409,7 @@ assignment_rule(Parser *p) && (_cut_var = 1) && - (c = _tmp_16_rule(p)) // yield_expr | star_expressions + (c = _tmp_17_rule(p)) // yield_expr | star_expressions ) { D(fprintf(stderr, "%*c+ assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "single_target augassign ~ (yield_expr | star_expressions)")); @@ -2899,7 +2968,7 @@ raise_stmt_rule(Parser *p) && (a = expression_rule(p)) // expression && - (b = _tmp_17_rule(p), !p->error_indicator) // ['from' expression] + (b = _tmp_18_rule(p), !p->error_indicator) // ['from' expression] ) { D(fprintf(stderr, "%*c+ raise_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'raise' expression ['from' expression]")); @@ -2997,7 +3066,7 @@ global_stmt_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 523)) // token='global' && - (a = (asdl_expr_seq*)_gather_18_rule(p)) // ','.NAME+ + (a = (asdl_expr_seq*)_gather_19_rule(p)) // ','.NAME+ ) { D(fprintf(stderr, "%*c+ global_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'global' ','.NAME+")); @@ -3062,7 +3131,7 @@ nonlocal_stmt_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 524)) // token='nonlocal' && - (a = (asdl_expr_seq*)_gather_20_rule(p)) // ','.NAME+ + (a = (asdl_expr_seq*)_gather_21_rule(p)) // ','.NAME+ ) { D(fprintf(stderr, "%*c+ nonlocal_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'nonlocal' ','.NAME+")); @@ -3125,11 +3194,11 @@ del_stmt_rule(Parser *p) Token * _keyword; asdl_expr_seq* a; if ( - (_keyword = _PyPegen_expect_token(p, 603)) // token='del' + (_keyword = _PyPegen_expect_token(p, 604)) // token='del' && (a = del_targets_rule(p)) // del_targets && - _PyPegen_lookahead(1, _tmp_22_rule, p) + _PyPegen_lookahead(1, _tmp_23_rule, p) ) { D(fprintf(stderr, "%*c+ del_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'del' del_targets &(';' | NEWLINE)")); @@ -3278,7 +3347,7 @@ assert_stmt_rule(Parser *p) && (a = expression_rule(p)) // expression && - (b = _tmp_23_rule(p), !p->error_indicator) // [',' expression] + (b = _tmp_24_rule(p), !p->error_indicator) // [',' expression] ) { D(fprintf(stderr, "%*c+ assert_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'assert' expression [',' expression]")); @@ -3418,7 +3487,7 @@ import_name_rule(Parser *p) Token * _keyword; asdl_alias_seq* a; if ( - (_keyword = _PyPegen_expect_token(p, 606)) // token='import' + (_keyword = _PyPegen_expect_token(p, 607)) // token='import' && (a = dotted_as_names_rule(p)) // dotted_as_names ) @@ -3488,13 +3557,13 @@ import_from_rule(Parser *p) expr_ty b; asdl_alias_seq* c; if ( - (_keyword = _PyPegen_expect_token(p, 607)) // token='from' + (_keyword = _PyPegen_expect_token(p, 608)) // token='from' && - (a = _loop0_24_rule(p)) // (('.' | '...'))* + (a = _loop0_25_rule(p)) // (('.' | '...'))* && (b = dotted_name_rule(p)) // dotted_name && - (_keyword_1 = _PyPegen_expect_token(p, 606)) // token='import' + (_keyword_1 = _PyPegen_expect_token(p, 607)) // token='import' && (c = import_from_targets_rule(p)) // import_from_targets ) @@ -3532,11 +3601,11 @@ import_from_rule(Parser *p) asdl_seq * a; asdl_alias_seq* b; if ( - (_keyword = _PyPegen_expect_token(p, 607)) // token='from' + (_keyword = _PyPegen_expect_token(p, 608)) // token='from' && - (a = _loop1_25_rule(p)) // (('.' | '...'))+ + (a = _loop1_26_rule(p)) // (('.' | '...'))+ && - (_keyword_1 = _PyPegen_expect_token(p, 606)) // token='import' + (_keyword_1 = _PyPegen_expect_token(p, 607)) // token='import' && (b = import_from_targets_rule(p)) // import_from_targets ) @@ -3731,7 +3800,7 @@ import_from_as_names_rule(Parser *p) D(fprintf(stderr, "%*c> import_from_as_names[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.import_from_as_name+")); asdl_alias_seq* a; if ( - (a = (asdl_alias_seq*)_gather_26_rule(p)) // ','.import_from_as_name+ + (a = (asdl_alias_seq*)_gather_27_rule(p)) // ','.import_from_as_name+ ) { D(fprintf(stderr, "%*c+ import_from_as_names[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.import_from_as_name+")); @@ -3787,7 +3856,7 @@ import_from_as_name_rule(Parser *p) if ( (a = _PyPegen_name_token(p)) // NAME && - (b = _tmp_28_rule(p), !p->error_indicator) // ['as' NAME] + (b = _tmp_29_rule(p), !p->error_indicator) // ['as' NAME] ) { D(fprintf(stderr, "%*c+ import_from_as_name[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME ['as' NAME]")); @@ -3840,7 +3909,7 @@ dotted_as_names_rule(Parser *p) D(fprintf(stderr, "%*c> dotted_as_names[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.dotted_as_name+")); asdl_alias_seq* a; if ( - (a = (asdl_alias_seq*)_gather_29_rule(p)) // ','.dotted_as_name+ + (a = (asdl_alias_seq*)_gather_30_rule(p)) // ','.dotted_as_name+ ) { D(fprintf(stderr, "%*c+ dotted_as_names[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.dotted_as_name+")); @@ -3896,7 +3965,7 @@ dotted_as_name_rule(Parser *p) if ( (a = dotted_name_rule(p)) // dotted_name && - (b = _tmp_31_rule(p), !p->error_indicator) // ['as' NAME] + (b = _tmp_32_rule(p), !p->error_indicator) // ['as' NAME] ) { D(fprintf(stderr, "%*c+ dotted_as_name[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_name ['as' NAME]")); @@ -4151,7 +4220,7 @@ decorators_rule(Parser *p) D(fprintf(stderr, "%*c> decorators[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(('@' named_expression NEWLINE))+")); asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_loop1_32_rule(p)) // (('@' named_expression NEWLINE))+ + (a = (asdl_expr_seq*)_loop1_33_rule(p)) // (('@' named_expression NEWLINE))+ ) { D(fprintf(stderr, "%*c+ decorators[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(('@' named_expression NEWLINE))+")); @@ -4293,11 +4362,11 @@ class_def_raw_rule(Parser *p) void *b; asdl_stmt_seq* c; if ( - (_keyword = _PyPegen_expect_token(p, 653)) // token='class' + (_keyword = _PyPegen_expect_token(p, 654)) // token='class' && (a = _PyPegen_name_token(p)) // NAME && - (b = _tmp_33_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (b = _tmp_34_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -4459,7 +4528,7 @@ function_def_raw_rule(Parser *p) void *params; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 651)) // token='def' + (_keyword = _PyPegen_expect_token(p, 652)) // token='def' && (n = _PyPegen_name_token(p)) // NAME && @@ -4469,7 +4538,7 @@ function_def_raw_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' && - (a = _tmp_34_rule(p), !p->error_indicator) // ['->' expression] + (a = _tmp_35_rule(p), !p->error_indicator) // ['->' expression] && (_literal_2 = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -4519,7 +4588,7 @@ function_def_raw_rule(Parser *p) if ( (async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC' && - (_keyword = _PyPegen_expect_token(p, 651)) // token='def' + (_keyword = _PyPegen_expect_token(p, 652)) // token='def' && (n = _PyPegen_name_token(p)) // NAME && @@ -4529,7 +4598,7 @@ function_def_raw_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' && - (a = _tmp_35_rule(p), !p->error_indicator) // ['->' expression] + (a = _tmp_36_rule(p), !p->error_indicator) // ['->' expression] && (_literal_2 = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -4656,9 +4725,9 @@ parameters_rule(Parser *p) if ( (a = slash_no_default_rule(p)) // slash_no_default && - (b = (asdl_arg_seq*)_loop0_36_rule(p)) // param_no_default* + (b = (asdl_arg_seq*)_loop0_37_rule(p)) // param_no_default* && - (c = _loop0_37_rule(p)) // param_with_default* + (c = _loop0_38_rule(p)) // param_with_default* && (d = star_etc_rule(p), !p->error_indicator) // star_etc? ) @@ -4688,7 +4757,7 @@ parameters_rule(Parser *p) if ( (a = slash_with_default_rule(p)) // slash_with_default && - (b = _loop0_38_rule(p)) // param_with_default* + (b = _loop0_39_rule(p)) // param_with_default* && (c = star_etc_rule(p), !p->error_indicator) // star_etc? ) @@ -4716,9 +4785,9 @@ parameters_rule(Parser *p) asdl_seq * b; void *c; if ( - (a = (asdl_arg_seq*)_loop1_39_rule(p)) // param_no_default+ + (a = (asdl_arg_seq*)_loop1_40_rule(p)) // param_no_default+ && - (b = _loop0_40_rule(p)) // param_with_default* + (b = _loop0_41_rule(p)) // param_with_default* && (c = star_etc_rule(p), !p->error_indicator) // star_etc? ) @@ -4745,7 +4814,7 @@ parameters_rule(Parser *p) asdl_seq * a; void *b; if ( - (a = _loop1_41_rule(p)) // param_with_default+ + (a = _loop1_42_rule(p)) // param_with_default+ && (b = star_etc_rule(p), !p->error_indicator) // star_etc? ) @@ -4817,7 +4886,7 @@ slash_no_default_rule(Parser *p) Token * _literal_1; asdl_arg_seq* a; if ( - (a = (asdl_arg_seq*)_loop1_42_rule(p)) // param_no_default+ + (a = (asdl_arg_seq*)_loop1_43_rule(p)) // param_no_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -4846,7 +4915,7 @@ slash_no_default_rule(Parser *p) Token * _literal; asdl_arg_seq* a; if ( - (a = (asdl_arg_seq*)_loop1_43_rule(p)) // param_no_default+ + (a = (asdl_arg_seq*)_loop1_44_rule(p)) // param_no_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -4899,9 +4968,9 @@ slash_with_default_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _loop0_44_rule(p)) // param_no_default* + (a = _loop0_45_rule(p)) // param_no_default* && - (b = _loop1_45_rule(p)) // param_with_default+ + (b = _loop1_46_rule(p)) // param_with_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -4931,9 +5000,9 @@ slash_with_default_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _loop0_46_rule(p)) // param_no_default* + (a = _loop0_47_rule(p)) // param_no_default* && - (b = _loop1_47_rule(p)) // param_with_default+ + (b = _loop1_48_rule(p)) // param_with_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -5012,7 +5081,7 @@ star_etc_rule(Parser *p) && (a = param_no_default_rule(p)) // param_no_default && - (b = _loop0_48_rule(p)) // param_maybe_default* + (b = _loop0_49_rule(p)) // param_maybe_default* && (c = kwds_rule(p), !p->error_indicator) // kwds? ) @@ -5045,7 +5114,7 @@ star_etc_rule(Parser *p) && (a = param_no_default_star_annotation_rule(p)) // param_no_default_star_annotation && - (b = _loop0_49_rule(p)) // param_maybe_default* + (b = _loop0_50_rule(p)) // param_maybe_default* && (c = kwds_rule(p), !p->error_indicator) // kwds? ) @@ -5078,7 +5147,7 @@ star_etc_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (b = _loop1_50_rule(p)) // param_maybe_default+ + (b = _loop1_51_rule(p)) // param_maybe_default+ && (c = kwds_rule(p), !p->error_indicator) // kwds? ) @@ -5871,7 +5940,7 @@ if_stmt_rule(Parser *p) asdl_stmt_seq* b; stmt_ty c; if ( - (_keyword = _PyPegen_expect_token(p, 641)) // token='if' + (_keyword = _PyPegen_expect_token(p, 642)) // token='if' && (a = named_expression_rule(p)) // named_expression && @@ -5916,7 +5985,7 @@ if_stmt_rule(Parser *p) asdl_stmt_seq* b; void *c; if ( - (_keyword = _PyPegen_expect_token(p, 641)) // token='if' + (_keyword = _PyPegen_expect_token(p, 642)) // token='if' && (a = named_expression_rule(p)) // named_expression && @@ -6012,7 +6081,7 @@ elif_stmt_rule(Parser *p) asdl_stmt_seq* b; stmt_ty c; if ( - (_keyword = _PyPegen_expect_token(p, 643)) // token='elif' + (_keyword = _PyPegen_expect_token(p, 644)) // token='elif' && (a = named_expression_rule(p)) // named_expression && @@ -6057,7 +6126,7 @@ elif_stmt_rule(Parser *p) asdl_stmt_seq* b; void *c; if ( - (_keyword = _PyPegen_expect_token(p, 643)) // token='elif' + (_keyword = _PyPegen_expect_token(p, 644)) // token='elif' && (a = named_expression_rule(p)) // named_expression && @@ -6139,7 +6208,7 @@ else_block_rule(Parser *p) Token * _literal; asdl_stmt_seq* b; if ( - (_keyword = _PyPegen_expect_token(p, 644)) // token='else' + (_keyword = _PyPegen_expect_token(p, 645)) // token='else' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -6219,7 +6288,7 @@ while_stmt_rule(Parser *p) asdl_stmt_seq* b; void *c; if ( - (_keyword = _PyPegen_expect_token(p, 646)) // token='while' + (_keyword = _PyPegen_expect_token(p, 647)) // token='while' && (a = named_expression_rule(p)) // named_expression && @@ -6320,11 +6389,11 @@ for_stmt_rule(Parser *p) expr_ty t; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 649)) // token='for' + (_keyword = _PyPegen_expect_token(p, 650)) // token='for' && (t = star_targets_rule(p)) // star_targets && - (_keyword_1 = _PyPegen_expect_token(p, 650)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 651)) // token='in' && (_cut_var = 1) && @@ -6384,11 +6453,11 @@ for_stmt_rule(Parser *p) if ( (async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC' && - (_keyword = _PyPegen_expect_token(p, 649)) // token='for' + (_keyword = _PyPegen_expect_token(p, 650)) // token='for' && (t = star_targets_rule(p)) // star_targets && - (_keyword_1 = _PyPegen_expect_token(p, 650)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 651)) // token='in' && (_cut_var = 1) && @@ -6517,11 +6586,11 @@ with_stmt_rule(Parser *p) asdl_withitem_seq* a; asdl_stmt_seq* b; if ( - (_keyword = _PyPegen_expect_token(p, 614)) // token='with' + (_keyword = _PyPegen_expect_token(p, 615)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = (asdl_withitem_seq*)_gather_51_rule(p)) // ','.with_item+ + (a = (asdl_withitem_seq*)_gather_52_rule(p)) // ','.with_item+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -6566,9 +6635,9 @@ with_stmt_rule(Parser *p) asdl_stmt_seq* b; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 614)) // token='with' + (_keyword = _PyPegen_expect_token(p, 615)) // token='with' && - (a = (asdl_withitem_seq*)_gather_53_rule(p)) // ','.with_item+ + (a = (asdl_withitem_seq*)_gather_54_rule(p)) // ','.with_item+ && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -6617,11 +6686,11 @@ with_stmt_rule(Parser *p) if ( (async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC' && - (_keyword = _PyPegen_expect_token(p, 614)) // token='with' + (_keyword = _PyPegen_expect_token(p, 615)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = (asdl_withitem_seq*)_gather_55_rule(p)) // ','.with_item+ + (a = (asdl_withitem_seq*)_gather_56_rule(p)) // ','.with_item+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -6669,9 +6738,9 @@ with_stmt_rule(Parser *p) if ( (async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC' && - (_keyword = _PyPegen_expect_token(p, 614)) // token='with' + (_keyword = _PyPegen_expect_token(p, 615)) // token='with' && - (a = (asdl_withitem_seq*)_gather_57_rule(p)) // ','.with_item+ + (a = (asdl_withitem_seq*)_gather_58_rule(p)) // ','.with_item+ && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -6756,11 +6825,11 @@ with_item_rule(Parser *p) if ( (e = expression_rule(p)) // expression && - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && (t = star_target_rule(p)) // star_target && - _PyPegen_lookahead(1, _tmp_59_rule, p) + _PyPegen_lookahead(1, _tmp_60_rule, p) ) { D(fprintf(stderr, "%*c+ with_item[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' star_target &(',' | ')' | ':')")); @@ -6882,7 +6951,7 @@ try_stmt_rule(Parser *p) asdl_stmt_seq* b; asdl_stmt_seq* f; if ( - (_keyword = _PyPegen_expect_token(p, 623)) // token='try' + (_keyword = _PyPegen_expect_token(p, 624)) // token='try' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -6926,13 +6995,13 @@ try_stmt_rule(Parser *p) asdl_excepthandler_seq* ex; void *f; if ( - (_keyword = _PyPegen_expect_token(p, 623)) // token='try' + (_keyword = _PyPegen_expect_token(p, 624)) // token='try' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && (b = block_rule(p)) // block && - (ex = (asdl_excepthandler_seq*)_loop1_60_rule(p)) // except_block+ + (ex = (asdl_excepthandler_seq*)_loop1_61_rule(p)) // except_block+ && (el = else_block_rule(p), !p->error_indicator) // else_block? && @@ -6974,13 +7043,13 @@ try_stmt_rule(Parser *p) asdl_excepthandler_seq* ex; void *f; if ( - (_keyword = _PyPegen_expect_token(p, 623)) // token='try' + (_keyword = _PyPegen_expect_token(p, 624)) // token='try' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && (b = block_rule(p)) // block && - (ex = (asdl_excepthandler_seq*)_loop1_61_rule(p)) // except_star_block+ + (ex = (asdl_excepthandler_seq*)_loop1_62_rule(p)) // except_star_block+ && (el = else_block_rule(p), !p->error_indicator) // else_block? && @@ -7073,11 +7142,11 @@ except_block_rule(Parser *p) expr_ty e; void *t; if ( - (_keyword = _PyPegen_expect_token(p, 636)) // token='except' + (_keyword = _PyPegen_expect_token(p, 637)) // token='except' && (e = expression_rule(p)) // expression && - (t = _tmp_62_rule(p), !p->error_indicator) // ['as' NAME] + (t = _tmp_63_rule(p), !p->error_indicator) // ['as' NAME] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -7116,7 +7185,7 @@ except_block_rule(Parser *p) Token * _literal; asdl_stmt_seq* b; if ( - (_keyword = _PyPegen_expect_token(p, 636)) // token='except' + (_keyword = _PyPegen_expect_token(p, 637)) // token='except' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -7228,13 +7297,13 @@ except_star_block_rule(Parser *p) expr_ty e; void *t; if ( - (_keyword = _PyPegen_expect_token(p, 636)) // token='except' + (_keyword = _PyPegen_expect_token(p, 637)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && (e = expression_rule(p)) // expression && - (t = _tmp_63_rule(p), !p->error_indicator) // ['as' NAME] + (t = _tmp_64_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -7331,7 +7400,7 @@ finally_block_rule(Parser *p) Token * _literal; asdl_stmt_seq* a; if ( - (_keyword = _PyPegen_expect_token(p, 632)) // token='finally' + (_keyword = _PyPegen_expect_token(p, 633)) // token='finally' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -7406,7 +7475,7 @@ match_stmt_rule(Parser *p) && (indent_var = _PyPegen_expect_token(p, INDENT)) // token='INDENT' && - (cases = (asdl_match_case_seq*)_loop1_64_rule(p)) // case_block+ + (cases = (asdl_match_case_seq*)_loop1_65_rule(p)) // case_block+ && (dedent_var = _PyPegen_expect_token(p, DEDENT)) // token='DEDENT' ) @@ -7643,7 +7712,7 @@ guard_rule(Parser *p) Token * _keyword; expr_ty guard; if ( - (_keyword = _PyPegen_expect_token(p, 641)) // token='if' + (_keyword = _PyPegen_expect_token(p, 642)) // token='if' && (guard = named_expression_rule(p)) // named_expression ) @@ -7841,7 +7910,7 @@ as_pattern_rule(Parser *p) if ( (pattern = or_pattern_rule(p)) // or_pattern && - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && (target = pattern_capture_target_rule(p)) // pattern_capture_target ) @@ -7924,7 +7993,7 @@ or_pattern_rule(Parser *p) D(fprintf(stderr, "%*c> or_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'|'.closed_pattern+")); asdl_pattern_seq* patterns; if ( - (patterns = (asdl_pattern_seq*)_gather_65_rule(p)) // '|'.closed_pattern+ + (patterns = (asdl_pattern_seq*)_gather_66_rule(p)) // '|'.closed_pattern+ ) { D(fprintf(stderr, "%*c+ or_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'|'.closed_pattern+")); @@ -8179,7 +8248,7 @@ literal_pattern_rule(Parser *p) if ( (value = signed_number_rule(p)) // signed_number && - _PyPegen_lookahead(0, _tmp_67_rule, p) + _PyPegen_lookahead(0, _tmp_68_rule, p) ) { D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "signed_number !('+' | '-')")); @@ -8278,7 +8347,7 @@ literal_pattern_rule(Parser *p) D(fprintf(stderr, "%*c> literal_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 601)) // token='None' + (_keyword = _PyPegen_expect_token(p, 602)) // token='None' ) { D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); @@ -8311,7 +8380,7 @@ literal_pattern_rule(Parser *p) D(fprintf(stderr, "%*c> literal_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 600)) // token='True' + (_keyword = _PyPegen_expect_token(p, 601)) // token='True' ) { D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); @@ -8344,7 +8413,7 @@ literal_pattern_rule(Parser *p) D(fprintf(stderr, "%*c> literal_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 602)) // token='False' + (_keyword = _PyPegen_expect_token(p, 603)) // token='False' ) { D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); @@ -8414,7 +8483,7 @@ literal_expr_rule(Parser *p) if ( (signed_number_var = signed_number_rule(p)) // signed_number && - _PyPegen_lookahead(0, _tmp_68_rule, p) + _PyPegen_lookahead(0, _tmp_69_rule, p) ) { D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "signed_number !('+' | '-')")); @@ -8471,7 +8540,7 @@ literal_expr_rule(Parser *p) D(fprintf(stderr, "%*c> literal_expr[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 601)) // token='None' + (_keyword = _PyPegen_expect_token(p, 602)) // token='None' ) { D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); @@ -8504,7 +8573,7 @@ literal_expr_rule(Parser *p) D(fprintf(stderr, "%*c> literal_expr[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 600)) // token='True' + (_keyword = _PyPegen_expect_token(p, 601)) // token='True' ) { D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); @@ -8537,7 +8606,7 @@ literal_expr_rule(Parser *p) D(fprintf(stderr, "%*c> literal_expr[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 602)) // token='False' + (_keyword = _PyPegen_expect_token(p, 603)) // token='False' ) { D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); @@ -9021,7 +9090,7 @@ pattern_capture_target_rule(Parser *p) && (name = _PyPegen_name_token(p)) // NAME && - _PyPegen_lookahead(0, _tmp_69_rule, p) + _PyPegen_lookahead(0, _tmp_70_rule, p) ) { D(fprintf(stderr, "%*c+ pattern_capture_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!\"_\" NAME !('.' | '(' | '=')")); @@ -9138,7 +9207,7 @@ value_pattern_rule(Parser *p) if ( (attr = attr_rule(p)) // attr && - _PyPegen_lookahead(0, _tmp_70_rule, p) + _PyPegen_lookahead(0, _tmp_71_rule, p) ) { D(fprintf(stderr, "%*c+ value_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "attr !('.' | '(' | '=')")); @@ -9564,7 +9633,7 @@ maybe_sequence_pattern_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_seq * patterns; if ( - (patterns = _gather_71_rule(p)) // ','.maybe_star_pattern+ + (patterns = _gather_72_rule(p)) // ','.maybe_star_pattern+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -9976,13 +10045,13 @@ items_pattern_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> items_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.key_value_pattern+")); - asdl_seq * _gather_73_var; + asdl_seq * _gather_74_var; if ( - (_gather_73_var = _gather_73_rule(p)) // ','.key_value_pattern+ + (_gather_74_var = _gather_74_rule(p)) // ','.key_value_pattern+ ) { D(fprintf(stderr, "%*c+ items_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.key_value_pattern+")); - _res = _gather_73_var; + _res = _gather_74_var; goto done; } p->mark = _mark; @@ -10019,7 +10088,7 @@ key_value_pattern_rule(Parser *p) void *key; pattern_ty pattern; if ( - (key = _tmp_75_rule(p)) // literal_expr | attr + (key = _tmp_76_rule(p)) // literal_expr | attr && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -10350,7 +10419,7 @@ positional_patterns_rule(Parser *p) D(fprintf(stderr, "%*c> positional_patterns[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.pattern+")); asdl_pattern_seq* args; if ( - (args = (asdl_pattern_seq*)_gather_76_rule(p)) // ','.pattern+ + (args = (asdl_pattern_seq*)_gather_77_rule(p)) // ','.pattern+ ) { D(fprintf(stderr, "%*c+ positional_patterns[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.pattern+")); @@ -10392,13 +10461,13 @@ keyword_patterns_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> keyword_patterns[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.keyword_pattern+")); - asdl_seq * _gather_78_var; + asdl_seq * _gather_79_var; if ( - (_gather_78_var = _gather_78_rule(p)) // ','.keyword_pattern+ + (_gather_79_var = _gather_79_rule(p)) // ','.keyword_pattern+ ) { D(fprintf(stderr, "%*c+ keyword_patterns[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.keyword_pattern+")); - _res = _gather_78_var; + _res = _gather_79_var; goto done; } p->mark = _mark; @@ -10497,7 +10566,7 @@ expressions_rule(Parser *p) if ( (a = expression_rule(p)) // expression && - (b = _loop1_80_rule(p)) // ((',' expression))+ + (b = _loop1_81_rule(p)) // ((',' expression))+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -10669,11 +10738,11 @@ expression_rule(Parser *p) if ( (a = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 641)) // token='if' + (_keyword = _PyPegen_expect_token(p, 642)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 644)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 645)) // token='else' && (c = expression_rule(p)) // expression ) @@ -10780,7 +10849,7 @@ yield_expr_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 573)) // token='yield' && - (_keyword_1 = _PyPegen_expect_token(p, 607)) // token='from' + (_keyword_1 = _PyPegen_expect_token(p, 608)) // token='from' && (a = expression_rule(p)) // expression ) @@ -10888,7 +10957,7 @@ star_expressions_rule(Parser *p) if ( (a = star_expression_rule(p)) // star_expression && - (b = _loop1_81_rule(p)) // ((',' star_expression))+ + (b = _loop1_82_rule(p)) // ((',' star_expression))+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -11089,7 +11158,7 @@ star_named_expressions_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_82_rule(p)) // ','.star_named_expression+ + (a = (asdl_expr_seq*)_gather_83_rule(p)) // ','.star_named_expression+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -11389,7 +11458,7 @@ disjunction_rule(Parser *p) if ( (a = conjunction_rule(p)) // conjunction && - (b = _loop1_84_rule(p)) // (('or' conjunction))+ + (b = _loop1_85_rule(p)) // (('or' conjunction))+ ) { D(fprintf(stderr, "%*c+ disjunction[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "conjunction (('or' conjunction))+")); @@ -11478,7 +11547,7 @@ conjunction_rule(Parser *p) if ( (a = inversion_rule(p)) // inversion && - (b = _loop1_85_rule(p)) // (('and' inversion))+ + (b = _loop1_86_rule(p)) // (('and' inversion))+ ) { D(fprintf(stderr, "%*c+ conjunction[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "inversion (('and' inversion))+")); @@ -11652,7 +11721,7 @@ comparison_rule(Parser *p) if ( (a = bitwise_or_rule(p)) // bitwise_or && - (b = _loop1_86_rule(p)) // compare_op_bitwise_or_pair+ + (b = _loop1_87_rule(p)) // compare_op_bitwise_or_pair+ ) { D(fprintf(stderr, "%*c+ comparison[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "bitwise_or compare_op_bitwise_or_pair+")); @@ -11989,10 +12058,10 @@ noteq_bitwise_or_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> noteq_bitwise_or[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('!=') bitwise_or")); - void *_tmp_87_var; + void *_tmp_88_var; expr_ty a; if ( - (_tmp_87_var = _tmp_87_rule(p)) // '!=' + (_tmp_88_var = _tmp_88_rule(p)) // '!=' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -12230,7 +12299,7 @@ notin_bitwise_or_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 581)) // token='not' && - (_keyword_1 = _PyPegen_expect_token(p, 650)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 651)) // token='in' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -12277,7 +12346,7 @@ in_bitwise_or_rule(Parser *p) Token * _keyword; expr_ty a; if ( - (_keyword = _PyPegen_expect_token(p, 650)) // token='in' + (_keyword = _PyPegen_expect_token(p, 651)) // token='in' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -14027,7 +14096,7 @@ slices_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_88_rule(p)) // ','.(slice | starred_expression)+ + (a = (asdl_expr_seq*)_gather_89_rule(p)) // ','.(slice | starred_expression)+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -14100,7 +14169,7 @@ slice_rule(Parser *p) && (b = expression_rule(p), !p->error_indicator) // expression? && - (c = _tmp_90_rule(p), !p->error_indicator) // [':' expression?] + (c = _tmp_91_rule(p), !p->error_indicator) // [':' expression?] ) { D(fprintf(stderr, "%*c+ slice[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression? ':' expression? [':' expression?]")); @@ -14160,7 +14229,7 @@ slice_rule(Parser *p) // | 'True' // | 'False' // | 'None' -// | &STRING strings +// | &(STRING | FSTRING_START) strings // | NUMBER // | &'(' (tuple | group | genexp) // | &'[' (list | listcomp) @@ -14215,7 +14284,7 @@ atom_rule(Parser *p) D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 600)) // token='True' + (_keyword = _PyPegen_expect_token(p, 601)) // token='True' ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); @@ -14248,7 +14317,7 @@ atom_rule(Parser *p) D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 602)) // token='False' + (_keyword = _PyPegen_expect_token(p, 603)) // token='False' ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); @@ -14281,7 +14350,7 @@ atom_rule(Parser *p) D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 601)) // token='None' + (_keyword = _PyPegen_expect_token(p, 602)) // token='None' ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); @@ -14306,26 +14375,26 @@ atom_rule(Parser *p) D(fprintf(stderr, "%*c%s atom[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'")); } - { // &STRING strings + { // &(STRING | FSTRING_START) strings if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&STRING strings")); + D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&(STRING | FSTRING_START) strings")); expr_ty strings_var; if ( - _PyPegen_lookahead(1, _PyPegen_string_token, p) + _PyPegen_lookahead(1, _tmp_92_rule, p) && (strings_var = strings_rule(p)) // strings ) { - D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&STRING strings")); + D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&(STRING | FSTRING_START) strings")); _res = strings_var; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s atom[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "&STRING strings")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "&(STRING | FSTRING_START) strings")); } { // NUMBER if (p->error_indicator) { @@ -14352,15 +14421,15 @@ atom_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'(' (tuple | group | genexp)")); - void *_tmp_91_var; + void *_tmp_93_var; if ( _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 7) // token='(' && - (_tmp_91_var = _tmp_91_rule(p)) // tuple | group | genexp + (_tmp_93_var = _tmp_93_rule(p)) // tuple | group | genexp ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'(' (tuple | group | genexp)")); - _res = _tmp_91_var; + _res = _tmp_93_var; goto done; } p->mark = _mark; @@ -14373,15 +14442,15 @@ atom_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'[' (list | listcomp)")); - void *_tmp_92_var; + void *_tmp_94_var; if ( _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 9) // token='[' && - (_tmp_92_var = _tmp_92_rule(p)) // list | listcomp + (_tmp_94_var = _tmp_94_rule(p)) // list | listcomp ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'[' (list | listcomp)")); - _res = _tmp_92_var; + _res = _tmp_94_var; goto done; } p->mark = _mark; @@ -14394,15 +14463,15 @@ atom_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'{' (dict | set | dictcomp | setcomp)")); - void *_tmp_93_var; + void *_tmp_95_var; if ( _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 25) // token='{' && - (_tmp_93_var = _tmp_93_rule(p)) // dict | set | dictcomp | setcomp + (_tmp_95_var = _tmp_95_rule(p)) // dict | set | dictcomp | setcomp ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'{' (dict | set | dictcomp | setcomp)")); - _res = _tmp_93_var; + _res = _tmp_95_var; goto done; } p->mark = _mark; @@ -14474,7 +14543,7 @@ group_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = _tmp_94_rule(p)) // yield_expr | named_expression + (a = _tmp_96_rule(p)) // yield_expr | named_expression && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) @@ -14551,7 +14620,7 @@ lambdef_rule(Parser *p) void *a; expr_ty b; if ( - (_keyword = _PyPegen_expect_token(p, 586)) // token='lambda' + (_keyword = _PyPegen_expect_token(p, 600)) // token='lambda' && (a = lambda_params_rule(p), !p->error_indicator) // lambda_params? && @@ -14678,9 +14747,9 @@ lambda_parameters_rule(Parser *p) if ( (a = lambda_slash_no_default_rule(p)) // lambda_slash_no_default && - (b = (asdl_arg_seq*)_loop0_95_rule(p)) // lambda_param_no_default* + (b = (asdl_arg_seq*)_loop0_97_rule(p)) // lambda_param_no_default* && - (c = _loop0_96_rule(p)) // lambda_param_with_default* + (c = _loop0_98_rule(p)) // lambda_param_with_default* && (d = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -14710,7 +14779,7 @@ lambda_parameters_rule(Parser *p) if ( (a = lambda_slash_with_default_rule(p)) // lambda_slash_with_default && - (b = _loop0_97_rule(p)) // lambda_param_with_default* + (b = _loop0_99_rule(p)) // lambda_param_with_default* && (c = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -14738,9 +14807,9 @@ lambda_parameters_rule(Parser *p) asdl_seq * b; void *c; if ( - (a = (asdl_arg_seq*)_loop1_98_rule(p)) // lambda_param_no_default+ + (a = (asdl_arg_seq*)_loop1_100_rule(p)) // lambda_param_no_default+ && - (b = _loop0_99_rule(p)) // lambda_param_with_default* + (b = _loop0_101_rule(p)) // lambda_param_with_default* && (c = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -14767,7 +14836,7 @@ lambda_parameters_rule(Parser *p) asdl_seq * a; void *b; if ( - (a = _loop1_100_rule(p)) // lambda_param_with_default+ + (a = _loop1_102_rule(p)) // lambda_param_with_default+ && (b = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -14841,7 +14910,7 @@ lambda_slash_no_default_rule(Parser *p) Token * _literal_1; asdl_arg_seq* a; if ( - (a = (asdl_arg_seq*)_loop1_101_rule(p)) // lambda_param_no_default+ + (a = (asdl_arg_seq*)_loop1_103_rule(p)) // lambda_param_no_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -14870,7 +14939,7 @@ lambda_slash_no_default_rule(Parser *p) Token * _literal; asdl_arg_seq* a; if ( - (a = (asdl_arg_seq*)_loop1_102_rule(p)) // lambda_param_no_default+ + (a = (asdl_arg_seq*)_loop1_104_rule(p)) // lambda_param_no_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -14923,9 +14992,9 @@ lambda_slash_with_default_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _loop0_103_rule(p)) // lambda_param_no_default* + (a = _loop0_105_rule(p)) // lambda_param_no_default* && - (b = _loop1_104_rule(p)) // lambda_param_with_default+ + (b = _loop1_106_rule(p)) // lambda_param_with_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -14955,9 +15024,9 @@ lambda_slash_with_default_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _loop0_105_rule(p)) // lambda_param_no_default* + (a = _loop0_107_rule(p)) // lambda_param_no_default* && - (b = _loop1_106_rule(p)) // lambda_param_with_default+ + (b = _loop1_108_rule(p)) // lambda_param_with_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -15035,7 +15104,7 @@ lambda_star_etc_rule(Parser *p) && (a = lambda_param_no_default_rule(p)) // lambda_param_no_default && - (b = _loop0_107_rule(p)) // lambda_param_maybe_default* + (b = _loop0_109_rule(p)) // lambda_param_maybe_default* && (c = lambda_kwds_rule(p), !p->error_indicator) // lambda_kwds? ) @@ -15068,7 +15137,7 @@ lambda_star_etc_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (b = _loop1_108_rule(p)) // lambda_param_maybe_default+ + (b = _loop1_110_rule(p)) // lambda_param_maybe_default+ && (c = lambda_kwds_rule(p), !p->error_indicator) // lambda_kwds? ) @@ -15475,7 +15544,387 @@ lambda_param_rule(Parser *p) return _res; } -// strings: STRING+ +// fstring_middle: fstring_replacement_field | FSTRING_MIDDLE +static expr_ty +fstring_middle_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + expr_ty _res = NULL; + int _mark = p->mark; + { // fstring_replacement_field + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> fstring_middle[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field")); + expr_ty fstring_replacement_field_var; + if ( + (fstring_replacement_field_var = fstring_replacement_field_rule(p)) // fstring_replacement_field + ) + { + D(fprintf(stderr, "%*c+ fstring_middle[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field")); + _res = fstring_replacement_field_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s fstring_middle[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_replacement_field")); + } + { // FSTRING_MIDDLE + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> fstring_middle[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE")); + Token * t; + if ( + (t = _PyPegen_expect_token(p, FSTRING_MIDDLE)) // token='FSTRING_MIDDLE' + ) + { + D(fprintf(stderr, "%*c+ fstring_middle[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE")); + _res = _PyPegen_constant_from_token ( p , t ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s fstring_middle[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_MIDDLE")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// fstring_replacement_field: +// | '{' (yield_expr | star_expressions) "="? fstring_conversion? fstring_full_format_spec? '}' +// | invalid_replacement_field +static expr_ty +fstring_replacement_field_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + expr_ty _res = NULL; + int _mark = p->mark; + if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { + p->error_indicator = 1; + p->level--; + return NULL; + } + int _start_lineno = p->tokens[_mark]->lineno; + UNUSED(_start_lineno); // Only used by EXTRA macro + int _start_col_offset = p->tokens[_mark]->col_offset; + UNUSED(_start_col_offset); // Only used by EXTRA macro + { // '{' (yield_expr | star_expressions) "="? fstring_conversion? fstring_full_format_spec? '}' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> fstring_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) \"=\"? fstring_conversion? fstring_full_format_spec? '}'")); + Token * _literal; + Token * _literal_1; + void *a; + void *conversion; + void *debug_expr; + void *format; + if ( + (_literal = _PyPegen_expect_token(p, 25)) // token='{' + && + (a = _tmp_111_rule(p)) // yield_expr | star_expressions + && + (debug_expr = _PyPegen_expect_token(p, 22), !p->error_indicator) // "="? + && + (conversion = fstring_conversion_rule(p), !p->error_indicator) // fstring_conversion? + && + (format = fstring_full_format_spec_rule(p), !p->error_indicator) // fstring_full_format_spec? + && + (_literal_1 = _PyPegen_expect_token(p, 26)) // token='}' + ) + { + D(fprintf(stderr, "%*c+ fstring_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) \"=\"? fstring_conversion? fstring_full_format_spec? '}'")); + Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); + if (_token == NULL) { + p->level--; + return NULL; + } + int _end_lineno = _token->end_lineno; + UNUSED(_end_lineno); // Only used by EXTRA macro + int _end_col_offset = _token->end_col_offset; + UNUSED(_end_col_offset); // Only used by EXTRA macro + _res = _PyPegen_formatted_value ( p , a , debug_expr , conversion , format , EXTRA ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s fstring_replacement_field[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' (yield_expr | star_expressions) \"=\"? fstring_conversion? fstring_full_format_spec? '}'")); + } + if (p->call_invalid_rules) { // invalid_replacement_field + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> fstring_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_replacement_field")); + void *invalid_replacement_field_var; + if ( + (invalid_replacement_field_var = invalid_replacement_field_rule(p)) // invalid_replacement_field + ) + { + D(fprintf(stderr, "%*c+ fstring_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_replacement_field")); + _res = invalid_replacement_field_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s fstring_replacement_field[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_replacement_field")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// fstring_conversion: "!" NAME +static expr_ty +fstring_conversion_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + expr_ty _res = NULL; + int _mark = p->mark; + { // "!" NAME + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> fstring_conversion[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "\"!\" NAME")); + expr_ty conv; + Token * conv_token; + if ( + (conv_token = _PyPegen_expect_token(p, 54)) // token='!' + && + (conv = _PyPegen_name_token(p)) // NAME + ) + { + D(fprintf(stderr, "%*c+ fstring_conversion[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "\"!\" NAME")); + _res = _PyPegen_check_fstring_conversion ( p , conv_token , conv ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s fstring_conversion[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "\"!\" NAME")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// fstring_full_format_spec: ':' fstring_format_spec* +static expr_ty +fstring_full_format_spec_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + expr_ty _res = NULL; + int _mark = p->mark; + if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { + p->error_indicator = 1; + p->level--; + return NULL; + } + int _start_lineno = p->tokens[_mark]->lineno; + UNUSED(_start_lineno); // Only used by EXTRA macro + int _start_col_offset = p->tokens[_mark]->col_offset; + UNUSED(_start_col_offset); // Only used by EXTRA macro + { // ':' fstring_format_spec* + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> fstring_full_format_spec[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':' fstring_format_spec*")); + Token * _literal; + asdl_seq * spec; + if ( + (_literal = _PyPegen_expect_token(p, 11)) // token=':' + && + (spec = _loop0_112_rule(p)) // fstring_format_spec* + ) + { + D(fprintf(stderr, "%*c+ fstring_full_format_spec[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' fstring_format_spec*")); + Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); + if (_token == NULL) { + p->level--; + return NULL; + } + int _end_lineno = _token->end_lineno; + UNUSED(_end_lineno); // Only used by EXTRA macro + int _end_col_offset = _token->end_col_offset; + UNUSED(_end_col_offset); // Only used by EXTRA macro + _res = spec ? _PyAST_JoinedStr ( ( asdl_expr_seq* ) spec , EXTRA ) : NULL; + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s fstring_full_format_spec[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':' fstring_format_spec*")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// fstring_format_spec: FSTRING_MIDDLE | fstring_replacement_field +static expr_ty +fstring_format_spec_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + expr_ty _res = NULL; + int _mark = p->mark; + { // FSTRING_MIDDLE + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> fstring_format_spec[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE")); + Token * t; + if ( + (t = _PyPegen_expect_token(p, FSTRING_MIDDLE)) // token='FSTRING_MIDDLE' + ) + { + D(fprintf(stderr, "%*c+ fstring_format_spec[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE")); + _res = _PyPegen_constant_from_token ( p , t ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s fstring_format_spec[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_MIDDLE")); + } + { // fstring_replacement_field + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> fstring_format_spec[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field")); + expr_ty fstring_replacement_field_var; + if ( + (fstring_replacement_field_var = fstring_replacement_field_rule(p)) // fstring_replacement_field + ) + { + D(fprintf(stderr, "%*c+ fstring_format_spec[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field")); + _res = fstring_replacement_field_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s fstring_format_spec[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_replacement_field")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// string: STRING +static expr_ty +string_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + expr_ty _res = NULL; + int _mark = p->mark; + { // STRING + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> string[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "STRING")); + Token* s; + if ( + (s = (Token*)_PyPegen_string_token(p)) // STRING + ) + { + D(fprintf(stderr, "%*c+ string[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "STRING")); + _res = _PyPegen_constant_from_string ( p , s ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s string[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "STRING")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// strings: ((fstring | string))+ static expr_ty strings_rule(Parser *p) { @@ -15493,19 +15942,37 @@ strings_rule(Parser *p) return _res; } int _mark = p->mark; - { // STRING+ + if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { + p->error_indicator = 1; + p->level--; + return NULL; + } + int _start_lineno = p->tokens[_mark]->lineno; + UNUSED(_start_lineno); // Only used by EXTRA macro + int _start_col_offset = p->tokens[_mark]->col_offset; + UNUSED(_start_col_offset); // Only used by EXTRA macro + { // ((fstring | string))+ if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> strings[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "STRING+")); - asdl_seq * a; + D(fprintf(stderr, "%*c> strings[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((fstring | string))+")); + asdl_expr_seq* a; if ( - (a = _loop1_109_rule(p)) // STRING+ + (a = (asdl_expr_seq*)_loop1_113_rule(p)) // ((fstring | string))+ ) { - D(fprintf(stderr, "%*c+ strings[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "STRING+")); - _res = _PyPegen_concatenate_strings ( p , a ); + D(fprintf(stderr, "%*c+ strings[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "((fstring | string))+")); + Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); + if (_token == NULL) { + p->level--; + return NULL; + } + int _end_lineno = _token->end_lineno; + UNUSED(_end_lineno); // Only used by EXTRA macro + int _end_col_offset = _token->end_col_offset; + UNUSED(_end_col_offset); // Only used by EXTRA macro + _res = _PyPegen_concatenate_strings ( p , a , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; p->level--; @@ -15515,7 +15982,7 @@ strings_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s strings[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "STRING+")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "((fstring | string))+")); } _res = NULL; done: @@ -15627,7 +16094,7 @@ tuple_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = _tmp_110_rule(p), !p->error_indicator) // [star_named_expression ',' star_named_expressions?] + (a = _tmp_114_rule(p), !p->error_indicator) // [star_named_expression ',' star_named_expressions?] && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) @@ -15845,7 +16312,7 @@ double_starred_kvpairs_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_seq * a; if ( - (a = _gather_111_rule(p)) // ','.double_starred_kvpair+ + (a = _gather_115_rule(p)) // ','.double_starred_kvpair+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -16007,7 +16474,7 @@ for_if_clauses_rule(Parser *p) D(fprintf(stderr, "%*c> for_if_clauses[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause+")); asdl_comprehension_seq* a; if ( - (a = (asdl_comprehension_seq*)_loop1_113_rule(p)) // for_if_clause+ + (a = (asdl_comprehension_seq*)_loop1_117_rule(p)) // for_if_clause+ ) { D(fprintf(stderr, "%*c+ for_if_clauses[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "for_if_clause+")); @@ -16062,17 +16529,17 @@ for_if_clause_rule(Parser *p) if ( (async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC' && - (_keyword = _PyPegen_expect_token(p, 649)) // token='for' + (_keyword = _PyPegen_expect_token(p, 650)) // token='for' && (a = star_targets_rule(p)) // star_targets && - (_keyword_1 = _PyPegen_expect_token(p, 650)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 651)) // token='in' && (_cut_var = 1) && (b = disjunction_rule(p)) // disjunction && - (c = (asdl_expr_seq*)_loop0_114_rule(p)) // (('if' disjunction))* + (c = (asdl_expr_seq*)_loop0_118_rule(p)) // (('if' disjunction))* ) { D(fprintf(stderr, "%*c+ for_if_clause[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC 'for' star_targets 'in' ~ disjunction (('if' disjunction))*")); @@ -16105,17 +16572,17 @@ for_if_clause_rule(Parser *p) expr_ty b; asdl_expr_seq* c; if ( - (_keyword = _PyPegen_expect_token(p, 649)) // token='for' + (_keyword = _PyPegen_expect_token(p, 650)) // token='for' && (a = star_targets_rule(p)) // star_targets && - (_keyword_1 = _PyPegen_expect_token(p, 650)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 651)) // token='in' && (_cut_var = 1) && (b = disjunction_rule(p)) // disjunction && - (c = (asdl_expr_seq*)_loop0_115_rule(p)) // (('if' disjunction))* + (c = (asdl_expr_seq*)_loop0_119_rule(p)) // (('if' disjunction))* ) { D(fprintf(stderr, "%*c+ for_if_clause[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'for' star_targets 'in' ~ disjunction (('if' disjunction))*")); @@ -16378,7 +16845,7 @@ genexp_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = _tmp_116_rule(p)) // assignment_expression | expression !':=' + (a = _tmp_120_rule(p)) // assignment_expression | expression !':=' && (b = for_if_clauses_rule(p)) // for_if_clauses && @@ -16630,9 +17097,9 @@ args_rule(Parser *p) asdl_expr_seq* a; void *b; if ( - (a = (asdl_expr_seq*)_gather_117_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ + (a = (asdl_expr_seq*)_gather_121_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ && - (b = _tmp_119_rule(p), !p->error_indicator) // [',' kwargs] + (b = _tmp_123_rule(p), !p->error_indicator) // [',' kwargs] ) { D(fprintf(stderr, "%*c+ args[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ [',' kwargs]")); @@ -16723,11 +17190,11 @@ kwargs_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _gather_120_rule(p)) // ','.kwarg_or_starred+ + (a = _gather_124_rule(p)) // ','.kwarg_or_starred+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (b = _gather_122_rule(p)) // ','.kwarg_or_double_starred+ + (b = _gather_126_rule(p)) // ','.kwarg_or_double_starred+ ) { D(fprintf(stderr, "%*c+ kwargs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_starred+ ',' ','.kwarg_or_double_starred+")); @@ -16749,13 +17216,13 @@ kwargs_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> kwargs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_starred+")); - asdl_seq * _gather_124_var; + asdl_seq * _gather_128_var; if ( - (_gather_124_var = _gather_124_rule(p)) // ','.kwarg_or_starred+ + (_gather_128_var = _gather_128_rule(p)) // ','.kwarg_or_starred+ ) { D(fprintf(stderr, "%*c+ kwargs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_starred+")); - _res = _gather_124_var; + _res = _gather_128_var; goto done; } p->mark = _mark; @@ -16768,13 +17235,13 @@ kwargs_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> kwargs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_double_starred+")); - asdl_seq * _gather_126_var; + asdl_seq * _gather_130_var; if ( - (_gather_126_var = _gather_126_rule(p)) // ','.kwarg_or_double_starred+ + (_gather_130_var = _gather_130_rule(p)) // ','.kwarg_or_double_starred+ ) { D(fprintf(stderr, "%*c+ kwargs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_double_starred+")); - _res = _gather_126_var; + _res = _gather_130_var; goto done; } p->mark = _mark; @@ -17167,7 +17634,7 @@ star_targets_rule(Parser *p) if ( (a = star_target_rule(p)) // star_target && - (b = _loop0_128_rule(p)) // ((',' star_target))* + (b = _loop0_132_rule(p)) // ((',' star_target))* && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -17224,7 +17691,7 @@ star_targets_list_seq_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_129_rule(p)) // ','.star_target+ + (a = (asdl_expr_seq*)_gather_133_rule(p)) // ','.star_target+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -17275,7 +17742,7 @@ star_targets_tuple_seq_rule(Parser *p) if ( (a = star_target_rule(p)) // star_target && - (b = _loop1_131_rule(p)) // ((',' star_target))+ + (b = _loop1_135_rule(p)) // ((',' star_target))+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -17364,7 +17831,7 @@ star_target_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (a = _tmp_132_rule(p)) // !'*' star_target + (a = _tmp_136_rule(p)) // !'*' star_target ) { D(fprintf(stderr, "%*c+ star_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (!'*' star_target)")); @@ -18295,7 +18762,7 @@ del_targets_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_133_rule(p)) // ','.del_target+ + (a = (asdl_expr_seq*)_gather_137_rule(p)) // ','.del_target+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -18656,7 +19123,7 @@ type_expressions_rule(Parser *p) expr_ty b; expr_ty c; if ( - (a = _gather_135_rule(p)) // ','.expression+ + (a = _gather_139_rule(p)) // ','.expression+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -18695,7 +19162,7 @@ type_expressions_rule(Parser *p) asdl_seq * a; expr_ty b; if ( - (a = _gather_137_rule(p)) // ','.expression+ + (a = _gather_141_rule(p)) // ','.expression+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -18728,7 +19195,7 @@ type_expressions_rule(Parser *p) asdl_seq * a; expr_ty b; if ( - (a = _gather_139_rule(p)) // ','.expression+ + (a = _gather_143_rule(p)) // ','.expression+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -18848,7 +19315,7 @@ type_expressions_rule(Parser *p) D(fprintf(stderr, "%*c> type_expressions[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.expression+")); asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_141_rule(p)) // ','.expression+ + (a = (asdl_expr_seq*)_gather_145_rule(p)) // ','.expression+ ) { D(fprintf(stderr, "%*c+ type_expressions[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.expression+")); @@ -18900,7 +19367,7 @@ func_type_comment_rule(Parser *p) && (t = _PyPegen_expect_token(p, TYPE_COMMENT)) // token='TYPE_COMMENT' && - _PyPegen_lookahead(1, _tmp_143_rule, p) + _PyPegen_lookahead(1, _tmp_147_rule, p) ) { D(fprintf(stderr, "%*c+ func_type_comment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE TYPE_COMMENT &(NEWLINE INDENT)")); @@ -19029,7 +19496,7 @@ invalid_arguments_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_opt_var = _tmp_144_rule(p), !p->error_indicator) // [args | expression for_if_clauses] + (_opt_var = _tmp_148_rule(p), !p->error_indicator) // [args | expression for_if_clauses] ) { D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses ',' [args | expression for_if_clauses]")); @@ -19089,13 +19556,13 @@ invalid_arguments_rule(Parser *p) expr_ty a; Token * b; if ( - (_opt_var = _tmp_145_rule(p), !p->error_indicator) // [(args ',')] + (_opt_var = _tmp_149_rule(p), !p->error_indicator) // [(args ',')] && (a = _PyPegen_name_token(p)) // NAME && (b = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(1, _tmp_146_rule, p) + _PyPegen_lookahead(1, _tmp_150_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "[(args ',')] NAME '=' &(',' | ')')")); @@ -19234,7 +19701,7 @@ invalid_kwarg_rule(Parser *p) Token* a; Token * b; if ( - (a = (Token*)_tmp_147_rule(p)) // 'True' | 'False' | 'None' + (a = (Token*)_tmp_151_rule(p)) // 'True' | 'False' | 'None' && (b = _PyPegen_expect_token(p, 22)) // token='=' ) @@ -19294,7 +19761,7 @@ invalid_kwarg_rule(Parser *p) expr_ty a; Token * b; if ( - _PyPegen_lookahead(0, _tmp_148_rule, p) + _PyPegen_lookahead(0, _tmp_152_rule, p) && (a = expression_rule(p)) // expression && @@ -19398,11 +19865,11 @@ expression_without_invalid_rule(Parser *p) if ( (a = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 641)) // token='if' + (_keyword = _PyPegen_expect_token(p, 642)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 644)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 645)) // token='else' && (c = expression_rule(p)) // expression ) @@ -19530,6 +19997,7 @@ invalid_legacy_expression_rule(Parser *p) // invalid_expression: // | !(NAME STRING | SOFT_KEYWORD) disjunction expression_without_invalid // | disjunction 'if' disjunction !('else' | ':') +// | 'lambda' lambda_params? ':' &(FSTRING_MIDDLE | fstring_replacement_field) static void * invalid_expression_rule(Parser *p) { @@ -19552,7 +20020,7 @@ invalid_expression_rule(Parser *p) expr_ty a; expr_ty b; if ( - _PyPegen_lookahead(0, _tmp_149_rule, p) + _PyPegen_lookahead(0, _tmp_153_rule, p) && (a = disjunction_rule(p)) // disjunction && @@ -19584,11 +20052,11 @@ invalid_expression_rule(Parser *p) if ( (a = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 641)) // token='if' + (_keyword = _PyPegen_expect_token(p, 642)) // token='if' && (b = disjunction_rule(p)) // disjunction && - _PyPegen_lookahead(0, _tmp_150_rule, p) + _PyPegen_lookahead(0, _tmp_154_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "disjunction 'if' disjunction !('else' | ':')")); @@ -19604,6 +20072,39 @@ invalid_expression_rule(Parser *p) D(fprintf(stderr, "%*c%s invalid_expression[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "disjunction 'if' disjunction !('else' | ':')")); } + { // 'lambda' lambda_params? ':' &(FSTRING_MIDDLE | fstring_replacement_field) + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_expression[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'lambda' lambda_params? ':' &(FSTRING_MIDDLE | fstring_replacement_field)")); + void *_opt_var; + UNUSED(_opt_var); // Silence compiler warnings + Token * a; + Token * b; + if ( + (a = _PyPegen_expect_token(p, 600)) // token='lambda' + && + (_opt_var = lambda_params_rule(p), !p->error_indicator) // lambda_params? + && + (b = _PyPegen_expect_token(p, 11)) // token=':' + && + _PyPegen_lookahead(1, _tmp_155_rule, p) + ) + { + D(fprintf(stderr, "%*c+ invalid_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'lambda' lambda_params? ':' &(FSTRING_MIDDLE | fstring_replacement_field)")); + _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "f-string: lambda expressions are not allowed without parentheses" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_expression[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'lambda' lambda_params? ':' &(FSTRING_MIDDLE | fstring_replacement_field)")); + } _res = NULL; done: p->level--; @@ -19677,7 +20178,7 @@ invalid_named_expression_rule(Parser *p) && (b = bitwise_or_rule(p)) // bitwise_or && - _PyPegen_lookahead(0, _tmp_151_rule, p) + _PyPegen_lookahead(0, _tmp_156_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_named_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '=' bitwise_or !('=' | ':=')")); @@ -19703,7 +20204,7 @@ invalid_named_expression_rule(Parser *p) Token * b; expr_ty bitwise_or_var; if ( - _PyPegen_lookahead(0, _tmp_152_rule, p) + _PyPegen_lookahead(0, _tmp_157_rule, p) && (a = bitwise_or_rule(p)) // bitwise_or && @@ -19711,7 +20212,7 @@ invalid_named_expression_rule(Parser *p) && (bitwise_or_var = bitwise_or_rule(p)) // bitwise_or && - _PyPegen_lookahead(0, _tmp_153_rule, p) + _PyPegen_lookahead(0, _tmp_158_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_named_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!(list | tuple | genexp | 'True' | 'None' | 'False') bitwise_or '=' bitwise_or !('=' | ':=')")); @@ -19792,7 +20293,7 @@ invalid_assignment_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions* ':' expression")); Token * _literal; Token * _literal_1; - asdl_seq * _loop0_154_var; + asdl_seq * _loop0_159_var; expr_ty a; expr_ty expression_var; if ( @@ -19800,7 +20301,7 @@ invalid_assignment_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_loop0_154_var = _loop0_154_rule(p)) // star_named_expressions* + (_loop0_159_var = _loop0_159_rule(p)) // star_named_expressions* && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -19857,10 +20358,10 @@ invalid_assignment_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* star_expressions '='")); Token * _literal; - asdl_seq * _loop0_155_var; + asdl_seq * _loop0_160_var; expr_ty a; if ( - (_loop0_155_var = _loop0_155_rule(p)) // ((star_targets '='))* + (_loop0_160_var = _loop0_160_rule(p)) // ((star_targets '='))* && (a = star_expressions_rule(p)) // star_expressions && @@ -19887,10 +20388,10 @@ invalid_assignment_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* yield_expr '='")); Token * _literal; - asdl_seq * _loop0_156_var; + asdl_seq * _loop0_161_var; expr_ty a; if ( - (_loop0_156_var = _loop0_156_rule(p)) // ((star_targets '='))* + (_loop0_161_var = _loop0_161_rule(p)) // ((star_targets '='))* && (a = yield_expr_rule(p)) // yield_expr && @@ -19916,7 +20417,7 @@ invalid_assignment_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions augassign (yield_expr | star_expressions)")); - void *_tmp_157_var; + void *_tmp_162_var; expr_ty a; AugOperator* augassign_var; if ( @@ -19924,7 +20425,7 @@ invalid_assignment_rule(Parser *p) && (augassign_var = augassign_rule(p)) // augassign && - (_tmp_157_var = _tmp_157_rule(p)) // yield_expr | star_expressions + (_tmp_162_var = _tmp_162_rule(p)) // yield_expr | star_expressions ) { D(fprintf(stderr, "%*c+ invalid_assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions augassign (yield_expr | star_expressions)")); @@ -20057,7 +20558,7 @@ invalid_del_stmt_rule(Parser *p) Token * _keyword; expr_ty a; if ( - (_keyword = _PyPegen_expect_token(p, 603)) // token='del' + (_keyword = _PyPegen_expect_token(p, 604)) // token='del' && (a = star_expressions_rule(p)) // star_expressions ) @@ -20150,11 +20651,11 @@ invalid_comprehension_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '(' | '{') starred_expression for_if_clauses")); - void *_tmp_158_var; + void *_tmp_163_var; expr_ty a; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_158_var = _tmp_158_rule(p)) // '[' | '(' | '{' + (_tmp_163_var = _tmp_163_rule(p)) // '[' | '(' | '{' && (a = starred_expression_rule(p)) // starred_expression && @@ -20181,12 +20682,12 @@ invalid_comprehension_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '{') star_named_expression ',' star_named_expressions for_if_clauses")); Token * _literal; - void *_tmp_159_var; + void *_tmp_164_var; expr_ty a; asdl_expr_seq* b; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_159_var = _tmp_159_rule(p)) // '[' | '{' + (_tmp_164_var = _tmp_164_rule(p)) // '[' | '{' && (a = star_named_expression_rule(p)) // star_named_expression && @@ -20216,12 +20717,12 @@ invalid_comprehension_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '{') star_named_expression ',' for_if_clauses")); - void *_tmp_160_var; + void *_tmp_165_var; expr_ty a; Token * b; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_160_var = _tmp_160_rule(p)) // '[' | '{' + (_tmp_165_var = _tmp_165_rule(p)) // '[' | '{' && (a = star_named_expression_rule(p)) // star_named_expression && @@ -20358,13 +20859,13 @@ invalid_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slash_no_default | slash_with_default) param_maybe_default* '/'")); - asdl_seq * _loop0_162_var; - void *_tmp_161_var; + asdl_seq * _loop0_167_var; + void *_tmp_166_var; Token * a; if ( - (_tmp_161_var = _tmp_161_rule(p)) // slash_no_default | slash_with_default + (_tmp_166_var = _tmp_166_rule(p)) // slash_no_default | slash_with_default && - (_loop0_162_var = _loop0_162_rule(p)) // param_maybe_default* + (_loop0_167_var = _loop0_167_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -20388,7 +20889,7 @@ invalid_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default? param_no_default* invalid_parameters_helper param_no_default")); - asdl_seq * _loop0_163_var; + asdl_seq * _loop0_168_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings arg_ty a; @@ -20396,7 +20897,7 @@ invalid_parameters_rule(Parser *p) if ( (_opt_var = slash_no_default_rule(p), !p->error_indicator) // slash_no_default? && - (_loop0_163_var = _loop0_163_rule(p)) // param_no_default* + (_loop0_168_var = _loop0_168_rule(p)) // param_no_default* && (invalid_parameters_helper_var = invalid_parameters_helper_rule(p)) // invalid_parameters_helper && @@ -20422,18 +20923,18 @@ invalid_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default* '(' param_no_default+ ','? ')'")); - asdl_seq * _loop0_164_var; - asdl_seq * _loop1_165_var; + asdl_seq * _loop0_169_var; + asdl_seq * _loop1_170_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; Token * b; if ( - (_loop0_164_var = _loop0_164_rule(p)) // param_no_default* + (_loop0_169_var = _loop0_169_rule(p)) // param_no_default* && (a = _PyPegen_expect_token(p, 7)) // token='(' && - (_loop1_165_var = _loop1_165_rule(p)) // param_no_default+ + (_loop1_170_var = _loop1_170_rule(p)) // param_no_default+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -20460,22 +20961,22 @@ invalid_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "[(slash_no_default | slash_with_default)] param_maybe_default* '*' (',' | param_no_default) param_maybe_default* '/'")); Token * _literal; - asdl_seq * _loop0_167_var; - asdl_seq * _loop0_169_var; + asdl_seq * _loop0_172_var; + asdl_seq * _loop0_174_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_168_var; + void *_tmp_173_var; Token * a; if ( - (_opt_var = _tmp_166_rule(p), !p->error_indicator) // [(slash_no_default | slash_with_default)] + (_opt_var = _tmp_171_rule(p), !p->error_indicator) // [(slash_no_default | slash_with_default)] && - (_loop0_167_var = _loop0_167_rule(p)) // param_maybe_default* + (_loop0_172_var = _loop0_172_rule(p)) // param_maybe_default* && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_168_var = _tmp_168_rule(p)) // ',' | param_no_default + (_tmp_173_var = _tmp_173_rule(p)) // ',' | param_no_default && - (_loop0_169_var = _loop0_169_rule(p)) // param_maybe_default* + (_loop0_174_var = _loop0_174_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -20500,10 +21001,10 @@ invalid_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default+ '/' '*'")); Token * _literal; - asdl_seq * _loop1_170_var; + asdl_seq * _loop1_175_var; Token * a; if ( - (_loop1_170_var = _loop1_170_rule(p)) // param_maybe_default+ + (_loop1_175_var = _loop1_175_rule(p)) // param_maybe_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -20553,7 +21054,7 @@ invalid_default_rule(Parser *p) if ( (a = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(1, _tmp_171_rule, p) + _PyPegen_lookahead(1, _tmp_176_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_default[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' &(')' | ',')")); @@ -20599,12 +21100,12 @@ invalid_star_etc_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))")); - void *_tmp_172_var; + void *_tmp_177_var; Token * a; if ( (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_172_var = _tmp_172_rule(p)) // ')' | ',' (')' | '**') + (_tmp_177_var = _tmp_177_rule(p)) // ')' | ',' (')' | '**') ) { D(fprintf(stderr, "%*c+ invalid_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))")); @@ -20687,20 +21188,20 @@ invalid_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (param_no_default | ',') param_maybe_default* '*' (param_no_default | ',')")); Token * _literal; - asdl_seq * _loop0_174_var; - void *_tmp_173_var; - void *_tmp_175_var; + asdl_seq * _loop0_179_var; + void *_tmp_178_var; + void *_tmp_180_var; Token * a; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_173_var = _tmp_173_rule(p)) // param_no_default | ',' + (_tmp_178_var = _tmp_178_rule(p)) // param_no_default | ',' && - (_loop0_174_var = _loop0_174_rule(p)) // param_maybe_default* + (_loop0_179_var = _loop0_179_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_175_var = _tmp_175_rule(p)) // param_no_default | ',' + (_tmp_180_var = _tmp_180_rule(p)) // param_no_default | ',' ) { D(fprintf(stderr, "%*c+ invalid_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (param_no_default | ',') param_maybe_default* '*' (param_no_default | ',')")); @@ -20816,7 +21317,7 @@ invalid_kwds_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (a = (Token*)_tmp_176_rule(p)) // '*' | '**' | '/' + (a = (Token*)_tmp_181_rule(p)) // '*' | '**' | '/' ) { D(fprintf(stderr, "%*c+ invalid_kwds[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' param ',' ('*' | '**' | '/')")); @@ -20882,13 +21383,13 @@ invalid_parameters_helper_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_parameters_helper[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default+")); - asdl_seq * _loop1_177_var; + asdl_seq * _loop1_182_var; if ( - (_loop1_177_var = _loop1_177_rule(p)) // param_with_default+ + (_loop1_182_var = _loop1_182_rule(p)) // param_with_default+ ) { D(fprintf(stderr, "%*c+ invalid_parameters_helper[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_with_default+")); - _res = _loop1_177_var; + _res = _loop1_182_var; goto done; } p->mark = _mark; @@ -20954,13 +21455,13 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(lambda_slash_no_default | lambda_slash_with_default) lambda_param_maybe_default* '/'")); - asdl_seq * _loop0_179_var; - void *_tmp_178_var; + asdl_seq * _loop0_184_var; + void *_tmp_183_var; Token * a; if ( - (_tmp_178_var = _tmp_178_rule(p)) // lambda_slash_no_default | lambda_slash_with_default + (_tmp_183_var = _tmp_183_rule(p)) // lambda_slash_no_default | lambda_slash_with_default && - (_loop0_179_var = _loop0_179_rule(p)) // lambda_param_maybe_default* + (_loop0_184_var = _loop0_184_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -20984,7 +21485,7 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default? lambda_param_no_default* invalid_lambda_parameters_helper lambda_param_no_default")); - asdl_seq * _loop0_180_var; + asdl_seq * _loop0_185_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings arg_ty a; @@ -20992,7 +21493,7 @@ invalid_lambda_parameters_rule(Parser *p) if ( (_opt_var = lambda_slash_no_default_rule(p), !p->error_indicator) // lambda_slash_no_default? && - (_loop0_180_var = _loop0_180_rule(p)) // lambda_param_no_default* + (_loop0_185_var = _loop0_185_rule(p)) // lambda_param_no_default* && (invalid_lambda_parameters_helper_var = invalid_lambda_parameters_helper_rule(p)) // invalid_lambda_parameters_helper && @@ -21018,18 +21519,18 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default* '(' ','.lambda_param+ ','? ')'")); - asdl_seq * _gather_182_var; - asdl_seq * _loop0_181_var; + asdl_seq * _gather_187_var; + asdl_seq * _loop0_186_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; Token * b; if ( - (_loop0_181_var = _loop0_181_rule(p)) // lambda_param_no_default* + (_loop0_186_var = _loop0_186_rule(p)) // lambda_param_no_default* && (a = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_182_var = _gather_182_rule(p)) // ','.lambda_param+ + (_gather_187_var = _gather_187_rule(p)) // ','.lambda_param+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -21056,22 +21557,22 @@ invalid_lambda_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "[(lambda_slash_no_default | lambda_slash_with_default)] lambda_param_maybe_default* '*' (',' | lambda_param_no_default) lambda_param_maybe_default* '/'")); Token * _literal; - asdl_seq * _loop0_185_var; - asdl_seq * _loop0_187_var; + asdl_seq * _loop0_190_var; + asdl_seq * _loop0_192_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_186_var; + void *_tmp_191_var; Token * a; if ( - (_opt_var = _tmp_184_rule(p), !p->error_indicator) // [(lambda_slash_no_default | lambda_slash_with_default)] + (_opt_var = _tmp_189_rule(p), !p->error_indicator) // [(lambda_slash_no_default | lambda_slash_with_default)] && - (_loop0_185_var = _loop0_185_rule(p)) // lambda_param_maybe_default* + (_loop0_190_var = _loop0_190_rule(p)) // lambda_param_maybe_default* && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_186_var = _tmp_186_rule(p)) // ',' | lambda_param_no_default + (_tmp_191_var = _tmp_191_rule(p)) // ',' | lambda_param_no_default && - (_loop0_187_var = _loop0_187_rule(p)) // lambda_param_maybe_default* + (_loop0_192_var = _loop0_192_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21096,10 +21597,10 @@ invalid_lambda_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default+ '/' '*'")); Token * _literal; - asdl_seq * _loop1_188_var; + asdl_seq * _loop1_193_var; Token * a; if ( - (_loop1_188_var = _loop1_188_rule(p)) // lambda_param_maybe_default+ + (_loop1_193_var = _loop1_193_rule(p)) // lambda_param_maybe_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -21171,13 +21672,13 @@ invalid_lambda_parameters_helper_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters_helper[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); - asdl_seq * _loop1_189_var; + asdl_seq * _loop1_194_var; if ( - (_loop1_189_var = _loop1_189_rule(p)) // lambda_param_with_default+ + (_loop1_194_var = _loop1_194_rule(p)) // lambda_param_with_default+ ) { D(fprintf(stderr, "%*c+ invalid_lambda_parameters_helper[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); - _res = _loop1_189_var; + _res = _loop1_194_var; goto done; } p->mark = _mark; @@ -21214,11 +21715,11 @@ invalid_lambda_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))")); Token * _literal; - void *_tmp_190_var; + void *_tmp_195_var; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_190_var = _tmp_190_rule(p)) // ':' | ',' (':' | '**') + (_tmp_195_var = _tmp_195_rule(p)) // ':' | ',' (':' | '**') ) { D(fprintf(stderr, "%*c+ invalid_lambda_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))")); @@ -21271,20 +21772,20 @@ invalid_lambda_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (lambda_param_no_default | ',') lambda_param_maybe_default* '*' (lambda_param_no_default | ',')")); Token * _literal; - asdl_seq * _loop0_192_var; - void *_tmp_191_var; - void *_tmp_193_var; + asdl_seq * _loop0_197_var; + void *_tmp_196_var; + void *_tmp_198_var; Token * a; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_191_var = _tmp_191_rule(p)) // lambda_param_no_default | ',' + (_tmp_196_var = _tmp_196_rule(p)) // lambda_param_no_default | ',' && - (_loop0_192_var = _loop0_192_rule(p)) // lambda_param_maybe_default* + (_loop0_197_var = _loop0_197_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_193_var = _tmp_193_rule(p)) // lambda_param_no_default | ',' + (_tmp_198_var = _tmp_198_rule(p)) // lambda_param_no_default | ',' ) { D(fprintf(stderr, "%*c+ invalid_lambda_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (lambda_param_no_default | ',') lambda_param_maybe_default* '*' (lambda_param_no_default | ',')")); @@ -21403,7 +21904,7 @@ invalid_lambda_kwds_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (a = (Token*)_tmp_194_rule(p)) // '*' | '**' | '/' + (a = (Token*)_tmp_199_rule(p)) // '*' | '**' | '/' ) { D(fprintf(stderr, "%*c+ invalid_lambda_kwds[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' lambda_param ',' ('*' | '**' | '/')")); @@ -21507,11 +22008,11 @@ invalid_with_item_rule(Parser *p) if ( (expression_var = expression_rule(p)) // expression && - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && (a = expression_rule(p)) // expression && - _PyPegen_lookahead(1, _tmp_195_rule, p) + _PyPegen_lookahead(1, _tmp_200_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_with_item[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' expression &(',' | ')' | ':')")); @@ -21560,7 +22061,7 @@ invalid_for_target_rule(Parser *p) if ( (_opt_var = _PyPegen_expect_token(p, ASYNC), !p->error_indicator) // ASYNC? && - (_keyword = _PyPegen_expect_token(p, 649)) // token='for' + (_keyword = _PyPegen_expect_token(p, 650)) // token='for' && (a = star_expressions_rule(p)) // star_expressions ) @@ -21692,11 +22193,11 @@ invalid_import_rule(Parser *p) expr_ty dotted_name_var; expr_ty dotted_name_var_1; if ( - (a = _PyPegen_expect_token(p, 606)) // token='import' + (a = _PyPegen_expect_token(p, 607)) // token='import' && (dotted_name_var = dotted_name_rule(p)) // dotted_name && - (_keyword = _PyPegen_expect_token(p, 607)) // token='from' + (_keyword = _PyPegen_expect_token(p, 608)) // token='from' && (dotted_name_var_1 = dotted_name_rule(p)) // dotted_name ) @@ -21792,7 +22293,7 @@ invalid_with_stmt_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' ','.(expression ['as' star_target])+ NEWLINE")); - asdl_seq * _gather_196_var; + asdl_seq * _gather_201_var; Token * _keyword; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings @@ -21800,9 +22301,9 @@ invalid_with_stmt_rule(Parser *p) if ( (_opt_var = _PyPegen_expect_token(p, ASYNC), !p->error_indicator) // ASYNC? && - (_keyword = _PyPegen_expect_token(p, 614)) // token='with' + (_keyword = _PyPegen_expect_token(p, 615)) // token='with' && - (_gather_196_var = _gather_196_rule(p)) // ','.(expression ['as' star_target])+ + (_gather_201_var = _gather_201_rule(p)) // ','.(expression ['as' star_target])+ && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -21826,7 +22327,7 @@ invalid_with_stmt_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' NEWLINE")); - asdl_seq * _gather_198_var; + asdl_seq * _gather_203_var; Token * _keyword; Token * _literal; Token * _literal_1; @@ -21838,11 +22339,11 @@ invalid_with_stmt_rule(Parser *p) if ( (_opt_var = _PyPegen_expect_token(p, ASYNC), !p->error_indicator) // ASYNC? && - (_keyword = _PyPegen_expect_token(p, 614)) // token='with' + (_keyword = _PyPegen_expect_token(p, 615)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_198_var = _gather_198_rule(p)) // ','.(expressions ['as' star_target])+ + (_gather_203_var = _gather_203_rule(p)) // ','.(expressions ['as' star_target])+ && (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -21892,7 +22393,7 @@ invalid_with_stmt_indent_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt_indent[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' ','.(expression ['as' star_target])+ ':' NEWLINE !INDENT")); - asdl_seq * _gather_200_var; + asdl_seq * _gather_205_var; Token * _literal; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings @@ -21901,9 +22402,9 @@ invalid_with_stmt_indent_rule(Parser *p) if ( (_opt_var = _PyPegen_expect_token(p, ASYNC), !p->error_indicator) // ASYNC? && - (a = _PyPegen_expect_token(p, 614)) // token='with' + (a = _PyPegen_expect_token(p, 615)) // token='with' && - (_gather_200_var = _gather_200_rule(p)) // ','.(expression ['as' star_target])+ + (_gather_205_var = _gather_205_rule(p)) // ','.(expression ['as' star_target])+ && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -21931,7 +22432,7 @@ invalid_with_stmt_indent_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt_indent[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' ':' NEWLINE !INDENT")); - asdl_seq * _gather_202_var; + asdl_seq * _gather_207_var; Token * _literal; Token * _literal_1; Token * _literal_2; @@ -21944,11 +22445,11 @@ invalid_with_stmt_indent_rule(Parser *p) if ( (_opt_var = _PyPegen_expect_token(p, ASYNC), !p->error_indicator) // ASYNC? && - (a = _PyPegen_expect_token(p, 614)) // token='with' + (a = _PyPegen_expect_token(p, 615)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_202_var = _gather_202_rule(p)) // ','.(expressions ['as' star_target])+ + (_gather_207_var = _gather_207_rule(p)) // ','.(expressions ['as' star_target])+ && (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -22008,7 +22509,7 @@ invalid_try_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 623)) // token='try' + (a = _PyPegen_expect_token(p, 624)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -22040,13 +22541,13 @@ invalid_try_stmt_rule(Parser *p) Token * _literal; asdl_stmt_seq* block_var; if ( - (_keyword = _PyPegen_expect_token(p, 623)) // token='try' + (_keyword = _PyPegen_expect_token(p, 624)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && (block_var = block_rule(p)) // block && - _PyPegen_lookahead(0, _tmp_204_rule, p) + _PyPegen_lookahead(0, _tmp_209_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_try_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'try' ':' block !('except' | 'finally')")); @@ -22071,29 +22572,29 @@ invalid_try_stmt_rule(Parser *p) Token * _keyword; Token * _literal; Token * _literal_1; - asdl_seq * _loop0_205_var; - asdl_seq * _loop1_206_var; + asdl_seq * _loop0_210_var; + asdl_seq * _loop1_211_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; Token * b; expr_ty expression_var; if ( - (_keyword = _PyPegen_expect_token(p, 623)) // token='try' + (_keyword = _PyPegen_expect_token(p, 624)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_205_var = _loop0_205_rule(p)) // block* + (_loop0_210_var = _loop0_210_rule(p)) // block* && - (_loop1_206_var = _loop1_206_rule(p)) // except_block+ + (_loop1_211_var = _loop1_211_rule(p)) // except_block+ && - (a = _PyPegen_expect_token(p, 636)) // token='except' + (a = _PyPegen_expect_token(p, 637)) // token='except' && (b = _PyPegen_expect_token(p, 16)) // token='*' && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_207_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_212_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -22120,23 +22621,23 @@ invalid_try_stmt_rule(Parser *p) Token * _keyword; Token * _literal; Token * _literal_1; - asdl_seq * _loop0_208_var; - asdl_seq * _loop1_209_var; + asdl_seq * _loop0_213_var; + asdl_seq * _loop1_214_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; if ( - (_keyword = _PyPegen_expect_token(p, 623)) // token='try' + (_keyword = _PyPegen_expect_token(p, 624)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_208_var = _loop0_208_rule(p)) // block* + (_loop0_213_var = _loop0_213_rule(p)) // block* && - (_loop1_209_var = _loop1_209_rule(p)) // except_star_block+ + (_loop1_214_var = _loop1_214_rule(p)) // except_star_block+ && - (a = _PyPegen_expect_token(p, 636)) // token='except' + (a = _PyPegen_expect_token(p, 637)) // token='except' && - (_opt_var = _tmp_210_rule(p), !p->error_indicator) // [expression ['as' NAME]] + (_opt_var = _tmp_215_rule(p), !p->error_indicator) // [expression ['as' NAME]] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -22194,7 +22695,7 @@ invalid_except_stmt_rule(Parser *p) expr_ty a; expr_ty expressions_var; if ( - (_keyword = _PyPegen_expect_token(p, 636)) // token='except' + (_keyword = _PyPegen_expect_token(p, 637)) // token='except' && (_opt_var = _PyPegen_expect_token(p, 16), !p->error_indicator) // '*'? && @@ -22204,7 +22705,7 @@ invalid_except_stmt_rule(Parser *p) && (expressions_var = expressions_rule(p)) // expressions && - (_opt_var_1 = _tmp_211_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var_1 = _tmp_216_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -22236,13 +22737,13 @@ invalid_except_stmt_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 636)) // token='except' + (a = _PyPegen_expect_token(p, 637)) // token='except' && (_opt_var = _PyPegen_expect_token(p, 16), !p->error_indicator) // '*'? && (expression_var = expression_rule(p)) // expression && - (_opt_var_1 = _tmp_212_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var_1 = _tmp_217_rule(p), !p->error_indicator) // ['as' NAME] && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -22269,7 +22770,7 @@ invalid_except_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 636)) // token='except' + (a = _PyPegen_expect_token(p, 637)) // token='except' && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -22294,14 +22795,14 @@ invalid_except_stmt_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_except_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')")); Token * _literal; - void *_tmp_213_var; + void *_tmp_218_var; Token * a; if ( - (a = _PyPegen_expect_token(p, 636)) // token='except' + (a = _PyPegen_expect_token(p, 637)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_213_var = _tmp_213_rule(p)) // NEWLINE | ':' + (_tmp_218_var = _tmp_218_rule(p)) // NEWLINE | ':' ) { D(fprintf(stderr, "%*c+ invalid_except_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')")); @@ -22347,7 +22848,7 @@ invalid_finally_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 632)) // token='finally' + (a = _PyPegen_expect_token(p, 633)) // token='finally' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -22404,11 +22905,11 @@ invalid_except_stmt_indent_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 636)) // token='except' + (a = _PyPegen_expect_token(p, 637)) // token='except' && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_214_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_219_rule(p), !p->error_indicator) // ['as' NAME] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -22440,7 +22941,7 @@ invalid_except_stmt_indent_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 636)) // token='except' + (a = _PyPegen_expect_token(p, 637)) // token='except' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -22497,13 +22998,13 @@ invalid_except_star_stmt_indent_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 636)) // token='except' + (a = _PyPegen_expect_token(p, 637)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_215_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_220_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -22739,7 +23240,7 @@ invalid_as_pattern_rule(Parser *p) if ( (or_pattern_var = or_pattern_rule(p)) // or_pattern && - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && (a = _PyPegen_expect_soft_keyword(p, "_")) // soft_keyword='"_"' ) @@ -22769,7 +23270,7 @@ invalid_as_pattern_rule(Parser *p) if ( (or_pattern_var = or_pattern_rule(p)) // or_pattern && - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && _PyPegen_lookahead_with_name(0, _PyPegen_name_token, p) && @@ -22872,7 +23373,7 @@ invalid_class_argument_pattern_rule(Parser *p) asdl_pattern_seq* a; asdl_seq* keyword_patterns_var; if ( - (_opt_var = _tmp_216_rule(p), !p->error_indicator) // [positional_patterns ','] + (_opt_var = _tmp_221_rule(p), !p->error_indicator) // [positional_patterns ','] && (keyword_patterns_var = keyword_patterns_rule(p)) // keyword_patterns && @@ -22926,7 +23427,7 @@ invalid_if_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 641)) // token='if' + (_keyword = _PyPegen_expect_token(p, 642)) // token='if' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -22957,7 +23458,7 @@ invalid_if_stmt_rule(Parser *p) expr_ty a_1; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 641)) // token='if' + (a = _PyPegen_expect_token(p, 642)) // token='if' && (a_1 = named_expression_rule(p)) // named_expression && @@ -23013,7 +23514,7 @@ invalid_elif_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 643)) // token='elif' + (_keyword = _PyPegen_expect_token(p, 644)) // token='elif' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -23044,7 +23545,7 @@ invalid_elif_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 643)) // token='elif' + (a = _PyPegen_expect_token(p, 644)) // token='elif' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -23098,7 +23599,7 @@ invalid_else_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 644)) // token='else' + (a = _PyPegen_expect_token(p, 645)) // token='else' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23152,7 +23653,7 @@ invalid_while_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 646)) // token='while' + (_keyword = _PyPegen_expect_token(p, 647)) // token='while' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -23183,7 +23684,7 @@ invalid_while_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 646)) // token='while' + (a = _PyPegen_expect_token(p, 647)) // token='while' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -23245,11 +23746,11 @@ invalid_for_stmt_rule(Parser *p) if ( (_opt_var = _PyPegen_expect_token(p, ASYNC), !p->error_indicator) // ASYNC? && - (_keyword = _PyPegen_expect_token(p, 649)) // token='for' + (_keyword = _PyPegen_expect_token(p, 650)) // token='for' && (star_targets_var = star_targets_rule(p)) // star_targets && - (_keyword_1 = _PyPegen_expect_token(p, 650)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 651)) // token='in' && (star_expressions_var = star_expressions_rule(p)) // star_expressions && @@ -23286,11 +23787,11 @@ invalid_for_stmt_rule(Parser *p) if ( (_opt_var = _PyPegen_expect_token(p, ASYNC), !p->error_indicator) // ASYNC? && - (a = _PyPegen_expect_token(p, 649)) // token='for' + (a = _PyPegen_expect_token(p, 650)) // token='for' && (star_targets_var = star_targets_rule(p)) // star_targets && - (_keyword = _PyPegen_expect_token(p, 650)) // token='in' + (_keyword = _PyPegen_expect_token(p, 651)) // token='in' && (star_expressions_var = star_expressions_rule(p)) // star_expressions && @@ -23356,7 +23857,7 @@ invalid_def_raw_rule(Parser *p) if ( (_opt_var = _PyPegen_expect_token(p, ASYNC), !p->error_indicator) // ASYNC? && - (a = _PyPegen_expect_token(p, 651)) // token='def' + (a = _PyPegen_expect_token(p, 652)) // token='def' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -23366,7 +23867,7 @@ invalid_def_raw_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' && - (_opt_var_2 = _tmp_217_rule(p), !p->error_indicator) // ['->' expression] + (_opt_var_2 = _tmp_222_rule(p), !p->error_indicator) // ['->' expression] && (_literal_2 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23422,11 +23923,11 @@ invalid_class_def_raw_rule(Parser *p) expr_ty name_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 653)) // token='class' + (_keyword = _PyPegen_expect_token(p, 654)) // token='class' && (name_var = _PyPegen_name_token(p)) // NAME && - (_opt_var = _tmp_218_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (_opt_var = _tmp_223_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -23457,11 +23958,11 @@ invalid_class_def_raw_rule(Parser *p) expr_ty name_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 653)) // token='class' + (a = _PyPegen_expect_token(p, 654)) // token='class' && (name_var = _PyPegen_name_token(p)) // NAME && - (_opt_var = _tmp_219_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (_opt_var = _tmp_224_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23512,11 +24013,11 @@ invalid_double_starred_kvpairs_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_double_starred_kvpairs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair")); - asdl_seq * _gather_220_var; + asdl_seq * _gather_225_var; Token * _literal; void *invalid_kvpair_var; if ( - (_gather_220_var = _gather_220_rule(p)) // ','.double_starred_kvpair+ + (_gather_225_var = _gather_225_rule(p)) // ','.double_starred_kvpair+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -23524,7 +24025,7 @@ invalid_double_starred_kvpairs_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair")); - _res = _PyPegen_dummy_name(p, _gather_220_var, _literal, invalid_kvpair_var); + _res = _PyPegen_dummy_name(p, _gather_225_var, _literal, invalid_kvpair_var); goto done; } p->mark = _mark; @@ -23577,7 +24078,7 @@ invalid_double_starred_kvpairs_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_222_rule, p) + _PyPegen_lookahead(1, _tmp_227_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -23688,7 +24189,7 @@ invalid_kvpair_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_223_rule, p) + _PyPegen_lookahead(1, _tmp_228_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_kvpair[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -23763,6 +24264,450 @@ invalid_starred_expression_rule(Parser *p) return _res; } +// invalid_replacement_field: +// | '{' '=' +// | '{' '!' +// | '{' ':' +// | '{' '}' +// | '{' !(yield_expr | star_expressions) +// | '{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}') +// | '{' (yield_expr | star_expressions) '=' !('!' | ':' | '}') +// | '{' (yield_expr | star_expressions) '='? invalid_conversion_character +// | '{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}') +// | '{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}' +// | '{' (yield_expr | star_expressions) '='? ['!' NAME] !'}' +static void * +invalid_replacement_field_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // '{' '=' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' '='")); + Token * _literal; + Token * a; + if ( + (_literal = _PyPegen_expect_token(p, 25)) // token='{' + && + (a = _PyPegen_expect_token(p, 22)) // token='=' + ) + { + D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' '='")); + _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "f-string: valid expression required before '='" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' '='")); + } + { // '{' '!' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' '!'")); + Token * _literal; + Token * a; + if ( + (_literal = _PyPegen_expect_token(p, 25)) // token='{' + && + (a = _PyPegen_expect_token(p, 54)) // token='!' + ) + { + D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' '!'")); + _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "f-string: valid expression required before '!'" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' '!'")); + } + { // '{' ':' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' ':'")); + Token * _literal; + Token * a; + if ( + (_literal = _PyPegen_expect_token(p, 25)) // token='{' + && + (a = _PyPegen_expect_token(p, 11)) // token=':' + ) + { + D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' ':'")); + _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "f-string: valid expression required before ':'" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' ':'")); + } + { // '{' '}' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' '}'")); + Token * _literal; + Token * a; + if ( + (_literal = _PyPegen_expect_token(p, 25)) // token='{' + && + (a = _PyPegen_expect_token(p, 26)) // token='}' + ) + { + D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' '}'")); + _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "f-string: valid expression required before '}'" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' '}'")); + } + { // '{' !(yield_expr | star_expressions) + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' !(yield_expr | star_expressions)")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 25)) // token='{' + && + _PyPegen_lookahead(0, _tmp_229_rule, p) + ) + { + D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' !(yield_expr | star_expressions)")); + _res = RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN ( "f-string: expecting a valid expression after '{'" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' !(yield_expr | star_expressions)")); + } + { // '{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}') + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}')")); + Token * _literal; + void *_tmp_230_var; + if ( + (_literal = _PyPegen_expect_token(p, 25)) // token='{' + && + (_tmp_230_var = _tmp_230_rule(p)) // yield_expr | star_expressions + && + _PyPegen_lookahead(0, _tmp_231_rule, p) + ) + { + D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}')")); + _res = PyErr_Occurred ( ) ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN ( "f-string: expecting '=', or '!', or ':', or '}'" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}')")); + } + { // '{' (yield_expr | star_expressions) '=' !('!' | ':' | '}') + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')")); + Token * _literal; + Token * _literal_1; + void *_tmp_232_var; + if ( + (_literal = _PyPegen_expect_token(p, 25)) // token='{' + && + (_tmp_232_var = _tmp_232_rule(p)) // yield_expr | star_expressions + && + (_literal_1 = _PyPegen_expect_token(p, 22)) // token='=' + && + _PyPegen_lookahead(0, _tmp_233_rule, p) + ) + { + D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')")); + _res = PyErr_Occurred ( ) ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN ( "f-string: expecting '!', or ':', or '}'" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')")); + } + { // '{' (yield_expr | star_expressions) '='? invalid_conversion_character + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? invalid_conversion_character")); + Token * _literal; + void *_opt_var; + UNUSED(_opt_var); // Silence compiler warnings + void *_tmp_234_var; + void *invalid_conversion_character_var; + if ( + (_literal = _PyPegen_expect_token(p, 25)) // token='{' + && + (_tmp_234_var = _tmp_234_rule(p)) // yield_expr | star_expressions + && + (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? + && + (invalid_conversion_character_var = invalid_conversion_character_rule(p)) // invalid_conversion_character + ) + { + D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? invalid_conversion_character")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_234_var, _opt_var, invalid_conversion_character_var); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' (yield_expr | star_expressions) '='? invalid_conversion_character")); + } + { // '{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}') + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}')")); + Token * _literal; + void *_opt_var; + UNUSED(_opt_var); // Silence compiler warnings + void *_opt_var_1; + UNUSED(_opt_var_1); // Silence compiler warnings + void *_tmp_235_var; + if ( + (_literal = _PyPegen_expect_token(p, 25)) // token='{' + && + (_tmp_235_var = _tmp_235_rule(p)) // yield_expr | star_expressions + && + (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? + && + (_opt_var_1 = _tmp_236_rule(p), !p->error_indicator) // ['!' NAME] + && + _PyPegen_lookahead(0, _tmp_237_rule, p) + ) + { + D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}')")); + _res = PyErr_Occurred ( ) ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN ( "f-string: expecting ':' or '}'" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}')")); + } + { // '{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}'")); + Token * _literal; + Token * _literal_1; + asdl_seq * _loop0_240_var; + void *_opt_var; + UNUSED(_opt_var); // Silence compiler warnings + void *_opt_var_1; + UNUSED(_opt_var_1); // Silence compiler warnings + void *_tmp_238_var; + if ( + (_literal = _PyPegen_expect_token(p, 25)) // token='{' + && + (_tmp_238_var = _tmp_238_rule(p)) // yield_expr | star_expressions + && + (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? + && + (_opt_var_1 = _tmp_239_rule(p), !p->error_indicator) // ['!' NAME] + && + (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' + && + (_loop0_240_var = _loop0_240_rule(p)) // fstring_format_spec* + && + _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' + ) + { + D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}'")); + _res = PyErr_Occurred ( ) ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN ( "f-string: expecting '}', or format specs" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}'")); + } + { // '{' (yield_expr | star_expressions) '='? ['!' NAME] !'}' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] !'}'")); + Token * _literal; + void *_opt_var; + UNUSED(_opt_var); // Silence compiler warnings + void *_opt_var_1; + UNUSED(_opt_var_1); // Silence compiler warnings + void *_tmp_241_var; + if ( + (_literal = _PyPegen_expect_token(p, 25)) // token='{' + && + (_tmp_241_var = _tmp_241_rule(p)) // yield_expr | star_expressions + && + (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? + && + (_opt_var_1 = _tmp_242_rule(p), !p->error_indicator) // ['!' NAME] + && + _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' + ) + { + D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] !'}'")); + _res = PyErr_Occurred ( ) ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN ( "f-string: expecting '}'" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] !'}'")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// invalid_conversion_character: '!' &(':' | '}') | '!' !NAME +static void * +invalid_conversion_character_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // '!' &(':' | '}') + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_conversion_character[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' &(':' | '}')")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 54)) // token='!' + && + _PyPegen_lookahead(1, _tmp_243_rule, p) + ) + { + D(fprintf(stderr, "%*c+ invalid_conversion_character[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' &(':' | '}')")); + _res = RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN ( "f-string: missing conversion character" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_conversion_character[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' &(':' | '}')")); + } + { // '!' !NAME + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_conversion_character[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' !NAME")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 54)) // token='!' + && + _PyPegen_lookahead_with_name(0, _PyPegen_name_token, p) + ) + { + D(fprintf(stderr, "%*c+ invalid_conversion_character[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' !NAME")); + _res = RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN ( "f-string: invalid conversion character" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_conversion_character[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' !NAME")); + } + _res = NULL; + done: + p->level--; + return _res; +} + // _loop0_1: NEWLINE static asdl_seq * _loop0_1_rule(Parser *p) @@ -23899,9 +24844,77 @@ _loop0_2_rule(Parser *p) return _seq; } -// _loop1_3: statement +// _loop0_3: fstring_middle static asdl_seq * -_loop1_3_rule(Parser *p) +_loop0_3_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // fstring_middle + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop0_3[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_middle")); + expr_ty fstring_middle_var; + while ( + (fstring_middle_var = fstring_middle_rule(p)) // fstring_middle + ) + { + _res = fstring_middle_var; + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop0_3[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_middle")); + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _loop1_4: statement +static asdl_seq * +_loop1_4_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -23927,7 +24940,7 @@ _loop1_3_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_3[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "statement")); + D(fprintf(stderr, "%*c> _loop1_4[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "statement")); asdl_stmt_seq* statement_var; while ( (statement_var = statement_rule(p)) // statement @@ -23950,7 +24963,7 @@ _loop1_3_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_3[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_4[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "statement")); } if (_n == 0 || p->error_indicator) { @@ -23972,9 +24985,9 @@ _loop1_3_rule(Parser *p) return _seq; } -// _loop0_5: ';' simple_stmt +// _loop0_6: ';' simple_stmt static asdl_seq * -_loop0_5_rule(Parser *p) +_loop0_6_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -24000,7 +25013,7 @@ _loop0_5_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_5[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "';' simple_stmt")); + D(fprintf(stderr, "%*c> _loop0_6[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "';' simple_stmt")); Token * _literal; stmt_ty elem; while ( @@ -24032,7 +25045,7 @@ _loop0_5_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_5[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_6[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "';' simple_stmt")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -24049,9 +25062,9 @@ _loop0_5_rule(Parser *p) return _seq; } -// _gather_4: simple_stmt _loop0_5 +// _gather_5: simple_stmt _loop0_6 static asdl_seq * -_gather_4_rule(Parser *p) +_gather_5_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -24063,27 +25076,27 @@ _gather_4_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // simple_stmt _loop0_5 + { // simple_stmt _loop0_6 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_4[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "simple_stmt _loop0_5")); + D(fprintf(stderr, "%*c> _gather_5[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "simple_stmt _loop0_6")); stmt_ty elem; asdl_seq * seq; if ( (elem = simple_stmt_rule(p)) // simple_stmt && - (seq = _loop0_5_rule(p)) // _loop0_5 + (seq = _loop0_6_rule(p)) // _loop0_6 ) { - D(fprintf(stderr, "%*c+ _gather_4[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "simple_stmt _loop0_5")); + D(fprintf(stderr, "%*c+ _gather_5[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "simple_stmt _loop0_6")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_4[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "simple_stmt _loop0_5")); + D(fprintf(stderr, "%*c%s _gather_5[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "simple_stmt _loop0_6")); } _res = NULL; done: @@ -24091,9 +25104,9 @@ _gather_4_rule(Parser *p) return _res; } -// _tmp_6: 'import' | 'from' +// _tmp_7: 'import' | 'from' static void * -_tmp_6_rule(Parser *p) +_tmp_7_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -24110,18 +25123,18 @@ _tmp_6_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_6[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'import'")); + D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'import'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 606)) // token='import' + (_keyword = _PyPegen_expect_token(p, 607)) // token='import' ) { - D(fprintf(stderr, "%*c+ _tmp_6[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'import'")); + D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'import'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_6[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_7[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'import'")); } { // 'from' @@ -24129,18 +25142,18 @@ _tmp_6_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_6[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from'")); + D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 607)) // token='from' + (_keyword = _PyPegen_expect_token(p, 608)) // token='from' ) { - D(fprintf(stderr, "%*c+ _tmp_6[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from'")); + D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_6[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_7[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'from'")); } _res = NULL; @@ -24149,9 +25162,9 @@ _tmp_6_rule(Parser *p) return _res; } -// _tmp_7: 'def' | '@' | ASYNC +// _tmp_8: 'def' | '@' | ASYNC static void * -_tmp_7_rule(Parser *p) +_tmp_8_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -24168,18 +25181,18 @@ _tmp_7_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'def'")); + D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'def'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 651)) // token='def' + (_keyword = _PyPegen_expect_token(p, 652)) // token='def' ) { - D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'def'")); + D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'def'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_7[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_8[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'def'")); } { // '@' @@ -24187,18 +25200,18 @@ _tmp_7_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@'")); + D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 49)) // token='@' ) { - D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@'")); + D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_7[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_8[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@'")); } { // ASYNC @@ -24206,18 +25219,18 @@ _tmp_7_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC")); + D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC")); Token * async_var; if ( (async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC' ) { - D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC")); + D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC")); _res = async_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_7[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_8[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "ASYNC")); } _res = NULL; @@ -24226,9 +25239,9 @@ _tmp_7_rule(Parser *p) return _res; } -// _tmp_8: 'class' | '@' +// _tmp_9: 'class' | '@' static void * -_tmp_8_rule(Parser *p) +_tmp_9_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -24245,18 +25258,18 @@ _tmp_8_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'class'")); + D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'class'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 653)) // token='class' + (_keyword = _PyPegen_expect_token(p, 654)) // token='class' ) { - D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'class'")); + D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'class'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_8[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_9[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'class'")); } { // '@' @@ -24264,18 +25277,18 @@ _tmp_8_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@'")); + D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 49)) // token='@' ) { - D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@'")); + D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_8[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_9[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@'")); } _res = NULL; @@ -24284,9 +25297,9 @@ _tmp_8_rule(Parser *p) return _res; } -// _tmp_9: 'with' | ASYNC +// _tmp_10: 'with' | ASYNC static void * -_tmp_9_rule(Parser *p) +_tmp_10_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -24303,18 +25316,18 @@ _tmp_9_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'with'")); + D(fprintf(stderr, "%*c> _tmp_10[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'with'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 614)) // token='with' + (_keyword = _PyPegen_expect_token(p, 615)) // token='with' ) { - D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'with'")); + D(fprintf(stderr, "%*c+ _tmp_10[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'with'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_9[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_10[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'with'")); } { // ASYNC @@ -24322,18 +25335,18 @@ _tmp_9_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC")); + D(fprintf(stderr, "%*c> _tmp_10[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC")); Token * async_var; if ( (async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC' ) { - D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC")); + D(fprintf(stderr, "%*c+ _tmp_10[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC")); _res = async_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_9[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_10[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "ASYNC")); } _res = NULL; @@ -24342,9 +25355,9 @@ _tmp_9_rule(Parser *p) return _res; } -// _tmp_10: 'for' | ASYNC +// _tmp_11: 'for' | ASYNC static void * -_tmp_10_rule(Parser *p) +_tmp_11_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -24361,18 +25374,18 @@ _tmp_10_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_10[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'for'")); + D(fprintf(stderr, "%*c> _tmp_11[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'for'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 649)) // token='for' + (_keyword = _PyPegen_expect_token(p, 650)) // token='for' ) { - D(fprintf(stderr, "%*c+ _tmp_10[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'for'")); + D(fprintf(stderr, "%*c+ _tmp_11[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'for'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_10[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_11[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'for'")); } { // ASYNC @@ -24380,18 +25393,18 @@ _tmp_10_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_10[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC")); + D(fprintf(stderr, "%*c> _tmp_11[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC")); Token * async_var; if ( (async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC' ) { - D(fprintf(stderr, "%*c+ _tmp_10[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC")); + D(fprintf(stderr, "%*c+ _tmp_11[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC")); _res = async_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_10[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_11[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "ASYNC")); } _res = NULL; @@ -24400,9 +25413,9 @@ _tmp_10_rule(Parser *p) return _res; } -// _tmp_11: '=' annotated_rhs +// _tmp_12: '=' annotated_rhs static void * -_tmp_11_rule(Parser *p) +_tmp_12_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -24419,7 +25432,7 @@ _tmp_11_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_11[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs")); + D(fprintf(stderr, "%*c> _tmp_12[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs")); Token * _literal; expr_ty d; if ( @@ -24428,7 +25441,7 @@ _tmp_11_rule(Parser *p) (d = annotated_rhs_rule(p)) // annotated_rhs ) { - D(fprintf(stderr, "%*c+ _tmp_11[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs")); + D(fprintf(stderr, "%*c+ _tmp_12[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs")); _res = d; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24438,7 +25451,7 @@ _tmp_11_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_11[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_12[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'=' annotated_rhs")); } _res = NULL; @@ -24447,9 +25460,9 @@ _tmp_11_rule(Parser *p) return _res; } -// _tmp_12: '(' single_target ')' | single_subscript_attribute_target +// _tmp_13: '(' single_target ')' | single_subscript_attribute_target static void * -_tmp_12_rule(Parser *p) +_tmp_13_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -24466,7 +25479,7 @@ _tmp_12_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_12[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' single_target ')'")); + D(fprintf(stderr, "%*c> _tmp_13[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' single_target ')'")); Token * _literal; Token * _literal_1; expr_ty b; @@ -24478,7 +25491,7 @@ _tmp_12_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_12[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' single_target ')'")); + D(fprintf(stderr, "%*c+ _tmp_13[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' single_target ')'")); _res = b; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24488,7 +25501,7 @@ _tmp_12_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_12[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_13[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' single_target ')'")); } { // single_subscript_attribute_target @@ -24496,18 +25509,18 @@ _tmp_12_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_12[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "single_subscript_attribute_target")); + D(fprintf(stderr, "%*c> _tmp_13[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "single_subscript_attribute_target")); expr_ty single_subscript_attribute_target_var; if ( (single_subscript_attribute_target_var = single_subscript_attribute_target_rule(p)) // single_subscript_attribute_target ) { - D(fprintf(stderr, "%*c+ _tmp_12[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "single_subscript_attribute_target")); + D(fprintf(stderr, "%*c+ _tmp_13[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "single_subscript_attribute_target")); _res = single_subscript_attribute_target_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_12[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_13[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "single_subscript_attribute_target")); } _res = NULL; @@ -24516,9 +25529,9 @@ _tmp_12_rule(Parser *p) return _res; } -// _tmp_13: '=' annotated_rhs +// _tmp_14: '=' annotated_rhs static void * -_tmp_13_rule(Parser *p) +_tmp_14_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -24535,7 +25548,7 @@ _tmp_13_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_13[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs")); + D(fprintf(stderr, "%*c> _tmp_14[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs")); Token * _literal; expr_ty d; if ( @@ -24544,7 +25557,7 @@ _tmp_13_rule(Parser *p) (d = annotated_rhs_rule(p)) // annotated_rhs ) { - D(fprintf(stderr, "%*c+ _tmp_13[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs")); + D(fprintf(stderr, "%*c+ _tmp_14[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs")); _res = d; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24554,7 +25567,7 @@ _tmp_13_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_13[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_14[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'=' annotated_rhs")); } _res = NULL; @@ -24563,9 +25576,9 @@ _tmp_13_rule(Parser *p) return _res; } -// _loop1_14: (star_targets '=') +// _loop1_15: (star_targets '=') static asdl_seq * -_loop1_14_rule(Parser *p) +_loop1_15_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -24591,13 +25604,13 @@ _loop1_14_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_14[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_224_var; + D(fprintf(stderr, "%*c> _loop1_15[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); + void *_tmp_244_var; while ( - (_tmp_224_var = _tmp_224_rule(p)) // star_targets '=' + (_tmp_244_var = _tmp_244_rule(p)) // star_targets '=' ) { - _res = _tmp_224_var; + _res = _tmp_244_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -24614,7 +25627,7 @@ _loop1_14_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_14[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_15[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')")); } if (_n == 0 || p->error_indicator) { @@ -24636,9 +25649,9 @@ _loop1_14_rule(Parser *p) return _seq; } -// _tmp_15: yield_expr | star_expressions +// _tmp_16: yield_expr | star_expressions static void * -_tmp_15_rule(Parser *p) +_tmp_16_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -24655,18 +25668,18 @@ _tmp_15_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_15[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_16[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_15[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_16[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_15[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_16[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -24674,18 +25687,18 @@ _tmp_15_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_15[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_16[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_15[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_16[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_15[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_16[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -24694,9 +25707,9 @@ _tmp_15_rule(Parser *p) return _res; } -// _tmp_16: yield_expr | star_expressions +// _tmp_17: yield_expr | star_expressions static void * -_tmp_16_rule(Parser *p) +_tmp_17_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -24713,18 +25726,18 @@ _tmp_16_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_16[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_17[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_16[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_17[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_16[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_17[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -24732,18 +25745,18 @@ _tmp_16_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_16[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_17[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_16[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_17[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_16[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_17[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -24752,9 +25765,9 @@ _tmp_16_rule(Parser *p) return _res; } -// _tmp_17: 'from' expression +// _tmp_18: 'from' expression static void * -_tmp_17_rule(Parser *p) +_tmp_18_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -24771,16 +25784,16 @@ _tmp_17_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_17[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from' expression")); + D(fprintf(stderr, "%*c> _tmp_18[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from' expression")); Token * _keyword; expr_ty z; if ( - (_keyword = _PyPegen_expect_token(p, 607)) // token='from' + (_keyword = _PyPegen_expect_token(p, 608)) // token='from' && (z = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_17[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from' expression")); + D(fprintf(stderr, "%*c+ _tmp_18[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from' expression")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -24790,7 +25803,7 @@ _tmp_17_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_17[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_18[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'from' expression")); } _res = NULL; @@ -24799,9 +25812,9 @@ _tmp_17_rule(Parser *p) return _res; } -// _loop0_19: ',' NAME +// _loop0_20: ',' NAME static asdl_seq * -_loop0_19_rule(Parser *p) +_loop0_20_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -24827,7 +25840,7 @@ _loop0_19_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_19[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' NAME")); + D(fprintf(stderr, "%*c> _loop0_20[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' NAME")); Token * _literal; expr_ty elem; while ( @@ -24859,7 +25872,7 @@ _loop0_19_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_19[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_20[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' NAME")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -24876,9 +25889,9 @@ _loop0_19_rule(Parser *p) return _seq; } -// _gather_18: NAME _loop0_19 +// _gather_19: NAME _loop0_20 static asdl_seq * -_gather_18_rule(Parser *p) +_gather_19_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -24890,27 +25903,27 @@ _gather_18_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // NAME _loop0_19 + { // NAME _loop0_20 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_18[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME _loop0_19")); + D(fprintf(stderr, "%*c> _gather_19[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME _loop0_20")); expr_ty elem; asdl_seq * seq; if ( (elem = _PyPegen_name_token(p)) // NAME && - (seq = _loop0_19_rule(p)) // _loop0_19 + (seq = _loop0_20_rule(p)) // _loop0_20 ) { - D(fprintf(stderr, "%*c+ _gather_18[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME _loop0_19")); + D(fprintf(stderr, "%*c+ _gather_19[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME _loop0_20")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_18[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME _loop0_19")); + D(fprintf(stderr, "%*c%s _gather_19[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME _loop0_20")); } _res = NULL; done: @@ -24918,9 +25931,9 @@ _gather_18_rule(Parser *p) return _res; } -// _loop0_21: ',' NAME +// _loop0_22: ',' NAME static asdl_seq * -_loop0_21_rule(Parser *p) +_loop0_22_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -24946,7 +25959,7 @@ _loop0_21_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_21[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' NAME")); + D(fprintf(stderr, "%*c> _loop0_22[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' NAME")); Token * _literal; expr_ty elem; while ( @@ -24978,7 +25991,7 @@ _loop0_21_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_21[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_22[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' NAME")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -24995,9 +26008,9 @@ _loop0_21_rule(Parser *p) return _seq; } -// _gather_20: NAME _loop0_21 +// _gather_21: NAME _loop0_22 static asdl_seq * -_gather_20_rule(Parser *p) +_gather_21_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -25009,27 +26022,27 @@ _gather_20_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // NAME _loop0_21 + { // NAME _loop0_22 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_20[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME _loop0_21")); + D(fprintf(stderr, "%*c> _gather_21[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME _loop0_22")); expr_ty elem; asdl_seq * seq; if ( (elem = _PyPegen_name_token(p)) // NAME && - (seq = _loop0_21_rule(p)) // _loop0_21 + (seq = _loop0_22_rule(p)) // _loop0_22 ) { - D(fprintf(stderr, "%*c+ _gather_20[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME _loop0_21")); + D(fprintf(stderr, "%*c+ _gather_21[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME _loop0_22")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_20[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME _loop0_21")); + D(fprintf(stderr, "%*c%s _gather_21[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME _loop0_22")); } _res = NULL; done: @@ -25037,9 +26050,9 @@ _gather_20_rule(Parser *p) return _res; } -// _tmp_22: ';' | NEWLINE +// _tmp_23: ';' | NEWLINE static void * -_tmp_22_rule(Parser *p) +_tmp_23_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -25056,18 +26069,18 @@ _tmp_22_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_22[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "';'")); + D(fprintf(stderr, "%*c> _tmp_23[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "';'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 13)) // token=';' ) { - D(fprintf(stderr, "%*c+ _tmp_22[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "';'")); + D(fprintf(stderr, "%*c+ _tmp_23[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "';'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_22[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_23[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "';'")); } { // NEWLINE @@ -25075,18 +26088,18 @@ _tmp_22_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_22[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_23[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); Token * newline_var; if ( (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_22[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_23[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); _res = newline_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_22[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_23[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE")); } _res = NULL; @@ -25095,9 +26108,9 @@ _tmp_22_rule(Parser *p) return _res; } -// _tmp_23: ',' expression +// _tmp_24: ',' expression static void * -_tmp_23_rule(Parser *p) +_tmp_24_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -25114,7 +26127,7 @@ _tmp_23_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_23[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _tmp_24[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty z; if ( @@ -25123,7 +26136,7 @@ _tmp_23_rule(Parser *p) (z = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_23[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c+ _tmp_24[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -25133,7 +26146,7 @@ _tmp_23_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_23[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_24[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } _res = NULL; @@ -25142,9 +26155,9 @@ _tmp_23_rule(Parser *p) return _res; } -// _loop0_24: ('.' | '...') +// _loop0_25: ('.' | '...') static asdl_seq * -_loop0_24_rule(Parser *p) +_loop0_25_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -25170,13 +26183,13 @@ _loop0_24_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_24[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_225_var; + D(fprintf(stderr, "%*c> _loop0_25[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); + void *_tmp_245_var; while ( - (_tmp_225_var = _tmp_225_rule(p)) // '.' | '...' + (_tmp_245_var = _tmp_245_rule(p)) // '.' | '...' ) { - _res = _tmp_225_var; + _res = _tmp_245_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -25193,7 +26206,7 @@ _loop0_24_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_24[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_25[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('.' | '...')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -25210,9 +26223,9 @@ _loop0_24_rule(Parser *p) return _seq; } -// _loop1_25: ('.' | '...') +// _loop1_26: ('.' | '...') static asdl_seq * -_loop1_25_rule(Parser *p) +_loop1_26_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -25238,13 +26251,13 @@ _loop1_25_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_25[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_226_var; + D(fprintf(stderr, "%*c> _loop1_26[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); + void *_tmp_246_var; while ( - (_tmp_226_var = _tmp_226_rule(p)) // '.' | '...' + (_tmp_246_var = _tmp_246_rule(p)) // '.' | '...' ) { - _res = _tmp_226_var; + _res = _tmp_246_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -25261,7 +26274,7 @@ _loop1_25_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_25[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_26[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('.' | '...')")); } if (_n == 0 || p->error_indicator) { @@ -25283,9 +26296,9 @@ _loop1_25_rule(Parser *p) return _seq; } -// _loop0_27: ',' import_from_as_name +// _loop0_28: ',' import_from_as_name static asdl_seq * -_loop0_27_rule(Parser *p) +_loop0_28_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -25311,7 +26324,7 @@ _loop0_27_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_27[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' import_from_as_name")); + D(fprintf(stderr, "%*c> _loop0_28[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' import_from_as_name")); Token * _literal; alias_ty elem; while ( @@ -25343,7 +26356,7 @@ _loop0_27_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_27[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_28[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' import_from_as_name")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -25360,9 +26373,9 @@ _loop0_27_rule(Parser *p) return _seq; } -// _gather_26: import_from_as_name _loop0_27 +// _gather_27: import_from_as_name _loop0_28 static asdl_seq * -_gather_26_rule(Parser *p) +_gather_27_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -25374,27 +26387,27 @@ _gather_26_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // import_from_as_name _loop0_27 + { // import_from_as_name _loop0_28 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_26[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "import_from_as_name _loop0_27")); + D(fprintf(stderr, "%*c> _gather_27[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "import_from_as_name _loop0_28")); alias_ty elem; asdl_seq * seq; if ( (elem = import_from_as_name_rule(p)) // import_from_as_name && - (seq = _loop0_27_rule(p)) // _loop0_27 + (seq = _loop0_28_rule(p)) // _loop0_28 ) { - D(fprintf(stderr, "%*c+ _gather_26[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "import_from_as_name _loop0_27")); + D(fprintf(stderr, "%*c+ _gather_27[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "import_from_as_name _loop0_28")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_26[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "import_from_as_name _loop0_27")); + D(fprintf(stderr, "%*c%s _gather_27[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "import_from_as_name _loop0_28")); } _res = NULL; done: @@ -25402,9 +26415,9 @@ _gather_26_rule(Parser *p) return _res; } -// _tmp_28: 'as' NAME +// _tmp_29: 'as' NAME static void * -_tmp_28_rule(Parser *p) +_tmp_29_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -25421,16 +26434,16 @@ _tmp_28_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_28[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_29[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty z; if ( - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && (z = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_28[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_29[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -25440,7 +26453,7 @@ _tmp_28_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_28[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_29[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -25449,9 +26462,9 @@ _tmp_28_rule(Parser *p) return _res; } -// _loop0_30: ',' dotted_as_name +// _loop0_31: ',' dotted_as_name static asdl_seq * -_loop0_30_rule(Parser *p) +_loop0_31_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -25477,7 +26490,7 @@ _loop0_30_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_30[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' dotted_as_name")); + D(fprintf(stderr, "%*c> _loop0_31[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' dotted_as_name")); Token * _literal; alias_ty elem; while ( @@ -25509,7 +26522,7 @@ _loop0_30_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_30[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_31[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' dotted_as_name")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -25526,9 +26539,9 @@ _loop0_30_rule(Parser *p) return _seq; } -// _gather_29: dotted_as_name _loop0_30 +// _gather_30: dotted_as_name _loop0_31 static asdl_seq * -_gather_29_rule(Parser *p) +_gather_30_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -25540,27 +26553,27 @@ _gather_29_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // dotted_as_name _loop0_30 + { // dotted_as_name _loop0_31 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_29[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_as_name _loop0_30")); + D(fprintf(stderr, "%*c> _gather_30[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_as_name _loop0_31")); alias_ty elem; asdl_seq * seq; if ( (elem = dotted_as_name_rule(p)) // dotted_as_name && - (seq = _loop0_30_rule(p)) // _loop0_30 + (seq = _loop0_31_rule(p)) // _loop0_31 ) { - D(fprintf(stderr, "%*c+ _gather_29[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_as_name _loop0_30")); + D(fprintf(stderr, "%*c+ _gather_30[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_as_name _loop0_31")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_29[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_as_name _loop0_30")); + D(fprintf(stderr, "%*c%s _gather_30[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_as_name _loop0_31")); } _res = NULL; done: @@ -25568,9 +26581,9 @@ _gather_29_rule(Parser *p) return _res; } -// _tmp_31: 'as' NAME +// _tmp_32: 'as' NAME static void * -_tmp_31_rule(Parser *p) +_tmp_32_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -25587,16 +26600,16 @@ _tmp_31_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_31[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_32[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty z; if ( - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && (z = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_31[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_32[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -25606,7 +26619,7 @@ _tmp_31_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_31[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_32[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -25615,9 +26628,9 @@ _tmp_31_rule(Parser *p) return _res; } -// _loop1_32: ('@' named_expression NEWLINE) +// _loop1_33: ('@' named_expression NEWLINE) static asdl_seq * -_loop1_32_rule(Parser *p) +_loop1_33_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -25643,13 +26656,13 @@ _loop1_32_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_32[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)")); - void *_tmp_227_var; + D(fprintf(stderr, "%*c> _loop1_33[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)")); + void *_tmp_247_var; while ( - (_tmp_227_var = _tmp_227_rule(p)) // '@' named_expression NEWLINE + (_tmp_247_var = _tmp_247_rule(p)) // '@' named_expression NEWLINE ) { - _res = _tmp_227_var; + _res = _tmp_247_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -25666,7 +26679,7 @@ _loop1_32_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_32[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_33[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('@' named_expression NEWLINE)")); } if (_n == 0 || p->error_indicator) { @@ -25688,9 +26701,9 @@ _loop1_32_rule(Parser *p) return _seq; } -// _tmp_33: '(' arguments? ')' +// _tmp_34: '(' arguments? ')' static void * -_tmp_33_rule(Parser *p) +_tmp_34_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -25707,7 +26720,7 @@ _tmp_33_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_33[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c> _tmp_34[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); Token * _literal; Token * _literal_1; void *z; @@ -25719,7 +26732,7 @@ _tmp_33_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_33[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c+ _tmp_34[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -25729,7 +26742,7 @@ _tmp_33_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_33[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_34[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'")); } _res = NULL; @@ -25738,9 +26751,9 @@ _tmp_33_rule(Parser *p) return _res; } -// _tmp_34: '->' expression +// _tmp_35: '->' expression static void * -_tmp_34_rule(Parser *p) +_tmp_35_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -25757,7 +26770,7 @@ _tmp_34_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_34[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c> _tmp_35[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); Token * _literal; expr_ty z; if ( @@ -25766,7 +26779,7 @@ _tmp_34_rule(Parser *p) (z = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_34[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c+ _tmp_35[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -25776,7 +26789,7 @@ _tmp_34_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_34[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_35[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'->' expression")); } _res = NULL; @@ -25785,9 +26798,9 @@ _tmp_34_rule(Parser *p) return _res; } -// _tmp_35: '->' expression +// _tmp_36: '->' expression static void * -_tmp_35_rule(Parser *p) +_tmp_36_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -25804,7 +26817,7 @@ _tmp_35_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_35[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c> _tmp_36[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); Token * _literal; expr_ty z; if ( @@ -25813,7 +26826,7 @@ _tmp_35_rule(Parser *p) (z = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_35[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c+ _tmp_36[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -25823,7 +26836,7 @@ _tmp_35_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_35[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_36[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'->' expression")); } _res = NULL; @@ -25832,9 +26845,9 @@ _tmp_35_rule(Parser *p) return _res; } -// _loop0_36: param_no_default +// _loop0_37: param_no_default static asdl_seq * -_loop0_36_rule(Parser *p) +_loop0_37_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -25860,7 +26873,7 @@ _loop0_36_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_36[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop0_37[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -25883,7 +26896,7 @@ _loop0_36_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_36[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_37[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -25900,9 +26913,9 @@ _loop0_36_rule(Parser *p) return _seq; } -// _loop0_37: param_with_default +// _loop0_38: param_with_default static asdl_seq * -_loop0_37_rule(Parser *p) +_loop0_38_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -25928,7 +26941,7 @@ _loop0_37_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_37[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop0_38[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -25951,7 +26964,7 @@ _loop0_37_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_37[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_38[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -25968,9 +26981,9 @@ _loop0_37_rule(Parser *p) return _seq; } -// _loop0_38: param_with_default +// _loop0_39: param_with_default static asdl_seq * -_loop0_38_rule(Parser *p) +_loop0_39_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -25996,7 +27009,7 @@ _loop0_38_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_38[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop0_39[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -26019,7 +27032,7 @@ _loop0_38_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_38[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_39[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -26036,9 +27049,9 @@ _loop0_38_rule(Parser *p) return _seq; } -// _loop1_39: param_no_default +// _loop1_40: param_no_default static asdl_seq * -_loop1_39_rule(Parser *p) +_loop1_40_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -26064,7 +27077,7 @@ _loop1_39_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_39[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop1_40[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -26087,7 +27100,7 @@ _loop1_39_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_39[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_40[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -26109,9 +27122,9 @@ _loop1_39_rule(Parser *p) return _seq; } -// _loop0_40: param_with_default +// _loop0_41: param_with_default static asdl_seq * -_loop0_40_rule(Parser *p) +_loop0_41_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -26137,7 +27150,7 @@ _loop0_40_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_40[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop0_41[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -26160,7 +27173,7 @@ _loop0_40_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_40[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_41[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -26177,9 +27190,9 @@ _loop0_40_rule(Parser *p) return _seq; } -// _loop1_41: param_with_default +// _loop1_42: param_with_default static asdl_seq * -_loop1_41_rule(Parser *p) +_loop1_42_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -26205,7 +27218,7 @@ _loop1_41_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_41[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop1_42[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -26228,7 +27241,7 @@ _loop1_41_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_41[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_42[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -26250,9 +27263,9 @@ _loop1_41_rule(Parser *p) return _seq; } -// _loop1_42: param_no_default +// _loop1_43: param_no_default static asdl_seq * -_loop1_42_rule(Parser *p) +_loop1_43_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -26278,7 +27291,7 @@ _loop1_42_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_42[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop1_43[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -26301,7 +27314,7 @@ _loop1_42_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_42[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_43[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -26323,9 +27336,9 @@ _loop1_42_rule(Parser *p) return _seq; } -// _loop1_43: param_no_default +// _loop1_44: param_no_default static asdl_seq * -_loop1_43_rule(Parser *p) +_loop1_44_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -26351,7 +27364,7 @@ _loop1_43_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_43[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop1_44[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -26374,7 +27387,7 @@ _loop1_43_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_43[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_44[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -26396,9 +27409,9 @@ _loop1_43_rule(Parser *p) return _seq; } -// _loop0_44: param_no_default +// _loop0_45: param_no_default static asdl_seq * -_loop0_44_rule(Parser *p) +_loop0_45_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -26424,7 +27437,7 @@ _loop0_44_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_44[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop0_45[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -26447,7 +27460,7 @@ _loop0_44_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_44[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_45[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -26464,9 +27477,9 @@ _loop0_44_rule(Parser *p) return _seq; } -// _loop1_45: param_with_default +// _loop1_46: param_with_default static asdl_seq * -_loop1_45_rule(Parser *p) +_loop1_46_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -26492,7 +27505,7 @@ _loop1_45_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_45[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop1_46[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -26515,7 +27528,7 @@ _loop1_45_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_45[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_46[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -26537,9 +27550,9 @@ _loop1_45_rule(Parser *p) return _seq; } -// _loop0_46: param_no_default +// _loop0_47: param_no_default static asdl_seq * -_loop0_46_rule(Parser *p) +_loop0_47_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -26565,7 +27578,7 @@ _loop0_46_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_46[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop0_47[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -26588,7 +27601,7 @@ _loop0_46_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_46[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_47[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -26605,9 +27618,9 @@ _loop0_46_rule(Parser *p) return _seq; } -// _loop1_47: param_with_default +// _loop1_48: param_with_default static asdl_seq * -_loop1_47_rule(Parser *p) +_loop1_48_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -26633,7 +27646,7 @@ _loop1_47_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_47[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop1_48[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -26656,7 +27669,7 @@ _loop1_47_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_47[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_48[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -26678,9 +27691,9 @@ _loop1_47_rule(Parser *p) return _seq; } -// _loop0_48: param_maybe_default +// _loop0_49: param_maybe_default static asdl_seq * -_loop0_48_rule(Parser *p) +_loop0_49_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -26706,7 +27719,7 @@ _loop0_48_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_48[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_49[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -26729,7 +27742,7 @@ _loop0_48_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_48[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_49[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -26746,9 +27759,9 @@ _loop0_48_rule(Parser *p) return _seq; } -// _loop0_49: param_maybe_default +// _loop0_50: param_maybe_default static asdl_seq * -_loop0_49_rule(Parser *p) +_loop0_50_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -26774,7 +27787,7 @@ _loop0_49_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_49[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_50[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -26797,7 +27810,7 @@ _loop0_49_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_49[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_50[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -26814,9 +27827,9 @@ _loop0_49_rule(Parser *p) return _seq; } -// _loop1_50: param_maybe_default +// _loop1_51: param_maybe_default static asdl_seq * -_loop1_50_rule(Parser *p) +_loop1_51_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -26842,7 +27855,7 @@ _loop1_50_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_50[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop1_51[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -26865,7 +27878,7 @@ _loop1_50_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_50[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_51[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } if (_n == 0 || p->error_indicator) { @@ -26887,9 +27900,9 @@ _loop1_50_rule(Parser *p) return _seq; } -// _loop0_52: ',' with_item +// _loop0_53: ',' with_item static asdl_seq * -_loop0_52_rule(Parser *p) +_loop0_53_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -26915,7 +27928,7 @@ _loop0_52_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_52[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item")); + D(fprintf(stderr, "%*c> _loop0_53[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item")); Token * _literal; withitem_ty elem; while ( @@ -26947,7 +27960,7 @@ _loop0_52_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_52[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_53[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' with_item")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -26964,9 +27977,9 @@ _loop0_52_rule(Parser *p) return _seq; } -// _gather_51: with_item _loop0_52 +// _gather_52: with_item _loop0_53 static asdl_seq * -_gather_51_rule(Parser *p) +_gather_52_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -26978,27 +27991,27 @@ _gather_51_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // with_item _loop0_52 + { // with_item _loop0_53 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_51[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_52")); + D(fprintf(stderr, "%*c> _gather_52[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_53")); withitem_ty elem; asdl_seq * seq; if ( (elem = with_item_rule(p)) // with_item && - (seq = _loop0_52_rule(p)) // _loop0_52 + (seq = _loop0_53_rule(p)) // _loop0_53 ) { - D(fprintf(stderr, "%*c+ _gather_51[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_52")); + D(fprintf(stderr, "%*c+ _gather_52[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_53")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_51[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_52")); + D(fprintf(stderr, "%*c%s _gather_52[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_53")); } _res = NULL; done: @@ -27006,9 +28019,9 @@ _gather_51_rule(Parser *p) return _res; } -// _loop0_54: ',' with_item +// _loop0_55: ',' with_item static asdl_seq * -_loop0_54_rule(Parser *p) +_loop0_55_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -27034,7 +28047,7 @@ _loop0_54_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_54[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item")); + D(fprintf(stderr, "%*c> _loop0_55[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item")); Token * _literal; withitem_ty elem; while ( @@ -27066,7 +28079,7 @@ _loop0_54_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_54[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_55[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' with_item")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -27083,9 +28096,9 @@ _loop0_54_rule(Parser *p) return _seq; } -// _gather_53: with_item _loop0_54 +// _gather_54: with_item _loop0_55 static asdl_seq * -_gather_53_rule(Parser *p) +_gather_54_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -27097,27 +28110,27 @@ _gather_53_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // with_item _loop0_54 + { // with_item _loop0_55 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_53[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_54")); + D(fprintf(stderr, "%*c> _gather_54[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_55")); withitem_ty elem; asdl_seq * seq; if ( (elem = with_item_rule(p)) // with_item && - (seq = _loop0_54_rule(p)) // _loop0_54 + (seq = _loop0_55_rule(p)) // _loop0_55 ) { - D(fprintf(stderr, "%*c+ _gather_53[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_54")); + D(fprintf(stderr, "%*c+ _gather_54[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_55")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_53[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_54")); + D(fprintf(stderr, "%*c%s _gather_54[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_55")); } _res = NULL; done: @@ -27125,9 +28138,9 @@ _gather_53_rule(Parser *p) return _res; } -// _loop0_56: ',' with_item +// _loop0_57: ',' with_item static asdl_seq * -_loop0_56_rule(Parser *p) +_loop0_57_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -27153,7 +28166,7 @@ _loop0_56_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_56[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item")); + D(fprintf(stderr, "%*c> _loop0_57[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item")); Token * _literal; withitem_ty elem; while ( @@ -27185,7 +28198,7 @@ _loop0_56_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_56[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_57[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' with_item")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -27202,9 +28215,9 @@ _loop0_56_rule(Parser *p) return _seq; } -// _gather_55: with_item _loop0_56 +// _gather_56: with_item _loop0_57 static asdl_seq * -_gather_55_rule(Parser *p) +_gather_56_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -27216,27 +28229,27 @@ _gather_55_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // with_item _loop0_56 + { // with_item _loop0_57 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_55[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_56")); + D(fprintf(stderr, "%*c> _gather_56[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_57")); withitem_ty elem; asdl_seq * seq; if ( (elem = with_item_rule(p)) // with_item && - (seq = _loop0_56_rule(p)) // _loop0_56 + (seq = _loop0_57_rule(p)) // _loop0_57 ) { - D(fprintf(stderr, "%*c+ _gather_55[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_56")); + D(fprintf(stderr, "%*c+ _gather_56[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_57")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_55[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_56")); + D(fprintf(stderr, "%*c%s _gather_56[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_57")); } _res = NULL; done: @@ -27244,9 +28257,9 @@ _gather_55_rule(Parser *p) return _res; } -// _loop0_58: ',' with_item +// _loop0_59: ',' with_item static asdl_seq * -_loop0_58_rule(Parser *p) +_loop0_59_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -27272,7 +28285,7 @@ _loop0_58_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_58[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item")); + D(fprintf(stderr, "%*c> _loop0_59[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item")); Token * _literal; withitem_ty elem; while ( @@ -27304,7 +28317,7 @@ _loop0_58_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_58[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_59[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' with_item")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -27321,9 +28334,9 @@ _loop0_58_rule(Parser *p) return _seq; } -// _gather_57: with_item _loop0_58 +// _gather_58: with_item _loop0_59 static asdl_seq * -_gather_57_rule(Parser *p) +_gather_58_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -27335,27 +28348,27 @@ _gather_57_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // with_item _loop0_58 + { // with_item _loop0_59 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_57[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_58")); + D(fprintf(stderr, "%*c> _gather_58[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_59")); withitem_ty elem; asdl_seq * seq; if ( (elem = with_item_rule(p)) // with_item && - (seq = _loop0_58_rule(p)) // _loop0_58 + (seq = _loop0_59_rule(p)) // _loop0_59 ) { - D(fprintf(stderr, "%*c+ _gather_57[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_58")); + D(fprintf(stderr, "%*c+ _gather_58[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_59")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_57[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_58")); + D(fprintf(stderr, "%*c%s _gather_58[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_59")); } _res = NULL; done: @@ -27363,9 +28376,9 @@ _gather_57_rule(Parser *p) return _res; } -// _tmp_59: ',' | ')' | ':' +// _tmp_60: ',' | ')' | ':' static void * -_tmp_59_rule(Parser *p) +_tmp_60_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -27382,18 +28395,18 @@ _tmp_59_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_59[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_60[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_59[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_60[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_59[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_60[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // ')' @@ -27401,18 +28414,18 @@ _tmp_59_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_59[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_60[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_59[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_60[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_59[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_60[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ':' @@ -27420,18 +28433,18 @@ _tmp_59_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_59[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_60[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_59[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_60[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_59[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_60[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -27440,9 +28453,9 @@ _tmp_59_rule(Parser *p) return _res; } -// _loop1_60: except_block +// _loop1_61: except_block static asdl_seq * -_loop1_60_rule(Parser *p) +_loop1_61_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -27468,7 +28481,7 @@ _loop1_60_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_60[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); + D(fprintf(stderr, "%*c> _loop1_61[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); excepthandler_ty except_block_var; while ( (except_block_var = except_block_rule(p)) // except_block @@ -27491,7 +28504,7 @@ _loop1_60_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_60[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_61[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_block")); } if (_n == 0 || p->error_indicator) { @@ -27513,9 +28526,9 @@ _loop1_60_rule(Parser *p) return _seq; } -// _loop1_61: except_star_block +// _loop1_62: except_star_block static asdl_seq * -_loop1_61_rule(Parser *p) +_loop1_62_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -27541,7 +28554,7 @@ _loop1_61_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_61[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); + D(fprintf(stderr, "%*c> _loop1_62[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); excepthandler_ty except_star_block_var; while ( (except_star_block_var = except_star_block_rule(p)) // except_star_block @@ -27564,7 +28577,7 @@ _loop1_61_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_61[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_62[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_star_block")); } if (_n == 0 || p->error_indicator) { @@ -27586,9 +28599,9 @@ _loop1_61_rule(Parser *p) return _seq; } -// _tmp_62: 'as' NAME +// _tmp_63: 'as' NAME static void * -_tmp_62_rule(Parser *p) +_tmp_63_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -27605,16 +28618,16 @@ _tmp_62_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_62[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_63[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty z; if ( - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && (z = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_62[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_63[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -27624,7 +28637,7 @@ _tmp_62_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_62[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_63[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -27633,9 +28646,9 @@ _tmp_62_rule(Parser *p) return _res; } -// _tmp_63: 'as' NAME +// _tmp_64: 'as' NAME static void * -_tmp_63_rule(Parser *p) +_tmp_64_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -27652,16 +28665,16 @@ _tmp_63_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_63[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_64[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty z; if ( - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && (z = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_63[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_64[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -27671,7 +28684,7 @@ _tmp_63_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_63[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_64[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -27680,9 +28693,9 @@ _tmp_63_rule(Parser *p) return _res; } -// _loop1_64: case_block +// _loop1_65: case_block static asdl_seq * -_loop1_64_rule(Parser *p) +_loop1_65_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -27708,7 +28721,7 @@ _loop1_64_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_64[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "case_block")); + D(fprintf(stderr, "%*c> _loop1_65[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "case_block")); match_case_ty case_block_var; while ( (case_block_var = case_block_rule(p)) // case_block @@ -27731,7 +28744,7 @@ _loop1_64_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_64[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_65[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "case_block")); } if (_n == 0 || p->error_indicator) { @@ -27753,9 +28766,9 @@ _loop1_64_rule(Parser *p) return _seq; } -// _loop0_66: '|' closed_pattern +// _loop0_67: '|' closed_pattern static asdl_seq * -_loop0_66_rule(Parser *p) +_loop0_67_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -27781,7 +28794,7 @@ _loop0_66_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_66[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'|' closed_pattern")); + D(fprintf(stderr, "%*c> _loop0_67[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'|' closed_pattern")); Token * _literal; pattern_ty elem; while ( @@ -27813,7 +28826,7 @@ _loop0_66_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_66[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_67[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'|' closed_pattern")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -27830,9 +28843,9 @@ _loop0_66_rule(Parser *p) return _seq; } -// _gather_65: closed_pattern _loop0_66 +// _gather_66: closed_pattern _loop0_67 static asdl_seq * -_gather_65_rule(Parser *p) +_gather_66_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -27844,85 +28857,27 @@ _gather_65_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // closed_pattern _loop0_66 + { // closed_pattern _loop0_67 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_65[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "closed_pattern _loop0_66")); + D(fprintf(stderr, "%*c> _gather_66[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "closed_pattern _loop0_67")); pattern_ty elem; asdl_seq * seq; if ( (elem = closed_pattern_rule(p)) // closed_pattern && - (seq = _loop0_66_rule(p)) // _loop0_66 + (seq = _loop0_67_rule(p)) // _loop0_67 ) { - D(fprintf(stderr, "%*c+ _gather_65[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "closed_pattern _loop0_66")); + D(fprintf(stderr, "%*c+ _gather_66[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "closed_pattern _loop0_67")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_65[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "closed_pattern _loop0_66")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _tmp_67: '+' | '-' -static void * -_tmp_67_rule(Parser *p) -{ - if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // '+' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_67[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 14)) // token='+' - ) - { - D(fprintf(stderr, "%*c+ _tmp_67[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_67[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'+'")); - } - { // '-' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_67[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 15)) // token='-' - ) - { - D(fprintf(stderr, "%*c+ _tmp_67[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_67[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'-'")); + D(fprintf(stderr, "%*c%s _gather_66[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "closed_pattern _loop0_67")); } _res = NULL; done: @@ -27988,7 +28943,7 @@ _tmp_68_rule(Parser *p) return _res; } -// _tmp_69: '.' | '(' | '=' +// _tmp_69: '+' | '-' static void * _tmp_69_rule(Parser *p) { @@ -28002,62 +28957,43 @@ _tmp_69_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // '.' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 23)) // token='.' - ) - { - D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); - } - { // '(' + { // '+' if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); Token * _literal; if ( - (_literal = _PyPegen_expect_token(p, 7)) // token='(' + (_literal = _PyPegen_expect_token(p, 14)) // token='+' ) { - D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); _res = _literal; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'+'")); } - { // '=' + { // '-' if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); Token * _literal; if ( - (_literal = _PyPegen_expect_token(p, 22)) // token='=' + (_literal = _PyPegen_expect_token(p, 15)) // token='-' ) { - D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); _res = _literal; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'-'")); } _res = NULL; done: @@ -28142,9 +29078,86 @@ _tmp_70_rule(Parser *p) return _res; } -// _loop0_72: ',' maybe_star_pattern +// _tmp_71: '.' | '(' | '=' +static void * +_tmp_71_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // '.' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 23)) // token='.' + ) + { + D(fprintf(stderr, "%*c+ _tmp_71[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_71[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); + } + { // '(' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 7)) // token='(' + ) + { + D(fprintf(stderr, "%*c+ _tmp_71[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_71[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('")); + } + { // '=' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 22)) // token='=' + ) + { + D(fprintf(stderr, "%*c+ _tmp_71[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_71[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _loop0_73: ',' maybe_star_pattern static asdl_seq * -_loop0_72_rule(Parser *p) +_loop0_73_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -28170,7 +29183,7 @@ _loop0_72_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_72[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' maybe_star_pattern")); + D(fprintf(stderr, "%*c> _loop0_73[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' maybe_star_pattern")); Token * _literal; pattern_ty elem; while ( @@ -28202,7 +29215,7 @@ _loop0_72_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_72[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_73[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' maybe_star_pattern")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -28219,9 +29232,9 @@ _loop0_72_rule(Parser *p) return _seq; } -// _gather_71: maybe_star_pattern _loop0_72 +// _gather_72: maybe_star_pattern _loop0_73 static asdl_seq * -_gather_71_rule(Parser *p) +_gather_72_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -28233,27 +29246,27 @@ _gather_71_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // maybe_star_pattern _loop0_72 + { // maybe_star_pattern _loop0_73 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_72")); + D(fprintf(stderr, "%*c> _gather_72[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_73")); pattern_ty elem; asdl_seq * seq; if ( (elem = maybe_star_pattern_rule(p)) // maybe_star_pattern && - (seq = _loop0_72_rule(p)) // _loop0_72 + (seq = _loop0_73_rule(p)) // _loop0_73 ) { - D(fprintf(stderr, "%*c+ _gather_71[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_72")); + D(fprintf(stderr, "%*c+ _gather_72[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_73")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_71[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "maybe_star_pattern _loop0_72")); + D(fprintf(stderr, "%*c%s _gather_72[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "maybe_star_pattern _loop0_73")); } _res = NULL; done: @@ -28261,9 +29274,9 @@ _gather_71_rule(Parser *p) return _res; } -// _loop0_74: ',' key_value_pattern +// _loop0_75: ',' key_value_pattern static asdl_seq * -_loop0_74_rule(Parser *p) +_loop0_75_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -28289,7 +29302,7 @@ _loop0_74_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_74[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' key_value_pattern")); + D(fprintf(stderr, "%*c> _loop0_75[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' key_value_pattern")); Token * _literal; KeyPatternPair* elem; while ( @@ -28321,7 +29334,7 @@ _loop0_74_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_74[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_75[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' key_value_pattern")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -28338,9 +29351,9 @@ _loop0_74_rule(Parser *p) return _seq; } -// _gather_73: key_value_pattern _loop0_74 +// _gather_74: key_value_pattern _loop0_75 static asdl_seq * -_gather_73_rule(Parser *p) +_gather_74_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -28352,27 +29365,27 @@ _gather_73_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // key_value_pattern _loop0_74 + { // key_value_pattern _loop0_75 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_73[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "key_value_pattern _loop0_74")); + D(fprintf(stderr, "%*c> _gather_74[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "key_value_pattern _loop0_75")); KeyPatternPair* elem; asdl_seq * seq; if ( (elem = key_value_pattern_rule(p)) // key_value_pattern && - (seq = _loop0_74_rule(p)) // _loop0_74 + (seq = _loop0_75_rule(p)) // _loop0_75 ) { - D(fprintf(stderr, "%*c+ _gather_73[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "key_value_pattern _loop0_74")); + D(fprintf(stderr, "%*c+ _gather_74[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "key_value_pattern _loop0_75")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_73[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "key_value_pattern _loop0_74")); + D(fprintf(stderr, "%*c%s _gather_74[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "key_value_pattern _loop0_75")); } _res = NULL; done: @@ -28380,9 +29393,9 @@ _gather_73_rule(Parser *p) return _res; } -// _tmp_75: literal_expr | attr +// _tmp_76: literal_expr | attr static void * -_tmp_75_rule(Parser *p) +_tmp_76_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -28399,18 +29412,18 @@ _tmp_75_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_75[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "literal_expr")); + D(fprintf(stderr, "%*c> _tmp_76[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "literal_expr")); expr_ty literal_expr_var; if ( (literal_expr_var = literal_expr_rule(p)) // literal_expr ) { - D(fprintf(stderr, "%*c+ _tmp_75[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "literal_expr")); + D(fprintf(stderr, "%*c+ _tmp_76[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "literal_expr")); _res = literal_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_75[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_76[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "literal_expr")); } { // attr @@ -28418,18 +29431,18 @@ _tmp_75_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_75[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "attr")); + D(fprintf(stderr, "%*c> _tmp_76[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "attr")); expr_ty attr_var; if ( (attr_var = attr_rule(p)) // attr ) { - D(fprintf(stderr, "%*c+ _tmp_75[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "attr")); + D(fprintf(stderr, "%*c+ _tmp_76[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "attr")); _res = attr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_75[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_76[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "attr")); } _res = NULL; @@ -28438,9 +29451,9 @@ _tmp_75_rule(Parser *p) return _res; } -// _loop0_77: ',' pattern +// _loop0_78: ',' pattern static asdl_seq * -_loop0_77_rule(Parser *p) +_loop0_78_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -28466,7 +29479,7 @@ _loop0_77_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_77[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' pattern")); + D(fprintf(stderr, "%*c> _loop0_78[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' pattern")); Token * _literal; pattern_ty elem; while ( @@ -28498,7 +29511,7 @@ _loop0_77_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_77[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_78[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' pattern")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -28515,9 +29528,9 @@ _loop0_77_rule(Parser *p) return _seq; } -// _gather_76: pattern _loop0_77 +// _gather_77: pattern _loop0_78 static asdl_seq * -_gather_76_rule(Parser *p) +_gather_77_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -28529,27 +29542,27 @@ _gather_76_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // pattern _loop0_77 + { // pattern _loop0_78 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_76[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "pattern _loop0_77")); + D(fprintf(stderr, "%*c> _gather_77[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "pattern _loop0_78")); pattern_ty elem; asdl_seq * seq; if ( (elem = pattern_rule(p)) // pattern && - (seq = _loop0_77_rule(p)) // _loop0_77 + (seq = _loop0_78_rule(p)) // _loop0_78 ) { - D(fprintf(stderr, "%*c+ _gather_76[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "pattern _loop0_77")); + D(fprintf(stderr, "%*c+ _gather_77[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "pattern _loop0_78")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_76[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "pattern _loop0_77")); + D(fprintf(stderr, "%*c%s _gather_77[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "pattern _loop0_78")); } _res = NULL; done: @@ -28557,9 +29570,9 @@ _gather_76_rule(Parser *p) return _res; } -// _loop0_79: ',' keyword_pattern +// _loop0_80: ',' keyword_pattern static asdl_seq * -_loop0_79_rule(Parser *p) +_loop0_80_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -28585,7 +29598,7 @@ _loop0_79_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_79[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' keyword_pattern")); + D(fprintf(stderr, "%*c> _loop0_80[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' keyword_pattern")); Token * _literal; KeyPatternPair* elem; while ( @@ -28617,7 +29630,7 @@ _loop0_79_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_79[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_80[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' keyword_pattern")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -28634,9 +29647,9 @@ _loop0_79_rule(Parser *p) return _seq; } -// _gather_78: keyword_pattern _loop0_79 +// _gather_79: keyword_pattern _loop0_80 static asdl_seq * -_gather_78_rule(Parser *p) +_gather_79_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -28648,27 +29661,27 @@ _gather_78_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // keyword_pattern _loop0_79 + { // keyword_pattern _loop0_80 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_78[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_79")); + D(fprintf(stderr, "%*c> _gather_79[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_80")); KeyPatternPair* elem; asdl_seq * seq; if ( (elem = keyword_pattern_rule(p)) // keyword_pattern && - (seq = _loop0_79_rule(p)) // _loop0_79 + (seq = _loop0_80_rule(p)) // _loop0_80 ) { - D(fprintf(stderr, "%*c+ _gather_78[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_79")); + D(fprintf(stderr, "%*c+ _gather_79[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_80")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_78[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "keyword_pattern _loop0_79")); + D(fprintf(stderr, "%*c%s _gather_79[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "keyword_pattern _loop0_80")); } _res = NULL; done: @@ -28676,9 +29689,9 @@ _gather_78_rule(Parser *p) return _res; } -// _loop1_80: (',' expression) +// _loop1_81: (',' expression) static asdl_seq * -_loop1_80_rule(Parser *p) +_loop1_81_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -28704,13 +29717,13 @@ _loop1_80_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_80[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' expression)")); - void *_tmp_228_var; + D(fprintf(stderr, "%*c> _loop1_81[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' expression)")); + void *_tmp_248_var; while ( - (_tmp_228_var = _tmp_228_rule(p)) // ',' expression + (_tmp_248_var = _tmp_248_rule(p)) // ',' expression ) { - _res = _tmp_228_var; + _res = _tmp_248_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -28727,7 +29740,7 @@ _loop1_80_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_80[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_81[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' expression)")); } if (_n == 0 || p->error_indicator) { @@ -28749,9 +29762,9 @@ _loop1_80_rule(Parser *p) return _seq; } -// _loop1_81: (',' star_expression) +// _loop1_82: (',' star_expression) static asdl_seq * -_loop1_81_rule(Parser *p) +_loop1_82_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -28777,13 +29790,13 @@ _loop1_81_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_81[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)")); - void *_tmp_229_var; + D(fprintf(stderr, "%*c> _loop1_82[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)")); + void *_tmp_249_var; while ( - (_tmp_229_var = _tmp_229_rule(p)) // ',' star_expression + (_tmp_249_var = _tmp_249_rule(p)) // ',' star_expression ) { - _res = _tmp_229_var; + _res = _tmp_249_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -28800,7 +29813,7 @@ _loop1_81_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_81[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_82[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_expression)")); } if (_n == 0 || p->error_indicator) { @@ -28822,9 +29835,9 @@ _loop1_81_rule(Parser *p) return _seq; } -// _loop0_83: ',' star_named_expression +// _loop0_84: ',' star_named_expression static asdl_seq * -_loop0_83_rule(Parser *p) +_loop0_84_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -28850,7 +29863,7 @@ _loop0_83_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_83[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_named_expression")); + D(fprintf(stderr, "%*c> _loop0_84[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_named_expression")); Token * _literal; expr_ty elem; while ( @@ -28882,7 +29895,7 @@ _loop0_83_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_83[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_84[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_named_expression")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -28899,9 +29912,9 @@ _loop0_83_rule(Parser *p) return _seq; } -// _gather_82: star_named_expression _loop0_83 +// _gather_83: star_named_expression _loop0_84 static asdl_seq * -_gather_82_rule(Parser *p) +_gather_83_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -28913,27 +29926,27 @@ _gather_82_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // star_named_expression _loop0_83 + { // star_named_expression _loop0_84 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_82[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_83")); + D(fprintf(stderr, "%*c> _gather_83[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_84")); expr_ty elem; asdl_seq * seq; if ( (elem = star_named_expression_rule(p)) // star_named_expression && - (seq = _loop0_83_rule(p)) // _loop0_83 + (seq = _loop0_84_rule(p)) // _loop0_84 ) { - D(fprintf(stderr, "%*c+ _gather_82[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_83")); + D(fprintf(stderr, "%*c+ _gather_83[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_84")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_82[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression _loop0_83")); + D(fprintf(stderr, "%*c%s _gather_83[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression _loop0_84")); } _res = NULL; done: @@ -28941,9 +29954,9 @@ _gather_82_rule(Parser *p) return _res; } -// _loop1_84: ('or' conjunction) +// _loop1_85: ('or' conjunction) static asdl_seq * -_loop1_84_rule(Parser *p) +_loop1_85_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -28969,13 +29982,13 @@ _loop1_84_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_84[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); - void *_tmp_230_var; + D(fprintf(stderr, "%*c> _loop1_85[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); + void *_tmp_250_var; while ( - (_tmp_230_var = _tmp_230_rule(p)) // 'or' conjunction + (_tmp_250_var = _tmp_250_rule(p)) // 'or' conjunction ) { - _res = _tmp_230_var; + _res = _tmp_250_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -28992,7 +30005,7 @@ _loop1_84_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_84[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_85[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('or' conjunction)")); } if (_n == 0 || p->error_indicator) { @@ -29014,9 +30027,9 @@ _loop1_84_rule(Parser *p) return _seq; } -// _loop1_85: ('and' inversion) +// _loop1_86: ('and' inversion) static asdl_seq * -_loop1_85_rule(Parser *p) +_loop1_86_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29042,13 +30055,13 @@ _loop1_85_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_85[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); - void *_tmp_231_var; + D(fprintf(stderr, "%*c> _loop1_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); + void *_tmp_251_var; while ( - (_tmp_231_var = _tmp_231_rule(p)) // 'and' inversion + (_tmp_251_var = _tmp_251_rule(p)) // 'and' inversion ) { - _res = _tmp_231_var; + _res = _tmp_251_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -29065,7 +30078,7 @@ _loop1_85_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_85[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_86[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('and' inversion)")); } if (_n == 0 || p->error_indicator) { @@ -29087,9 +30100,9 @@ _loop1_85_rule(Parser *p) return _seq; } -// _loop1_86: compare_op_bitwise_or_pair +// _loop1_87: compare_op_bitwise_or_pair static asdl_seq * -_loop1_86_rule(Parser *p) +_loop1_87_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29115,7 +30128,7 @@ _loop1_86_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "compare_op_bitwise_or_pair")); + D(fprintf(stderr, "%*c> _loop1_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "compare_op_bitwise_or_pair")); CmpopExprPair* compare_op_bitwise_or_pair_var; while ( (compare_op_bitwise_or_pair_var = compare_op_bitwise_or_pair_rule(p)) // compare_op_bitwise_or_pair @@ -29138,7 +30151,7 @@ _loop1_86_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_86[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_87[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "compare_op_bitwise_or_pair")); } if (_n == 0 || p->error_indicator) { @@ -29160,9 +30173,9 @@ _loop1_86_rule(Parser *p) return _seq; } -// _tmp_87: '!=' +// _tmp_88: '!=' static void * -_tmp_87_rule(Parser *p) +_tmp_88_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29179,13 +30192,13 @@ _tmp_87_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!='")); + D(fprintf(stderr, "%*c> _tmp_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!='")); Token * tok; if ( (tok = _PyPegen_expect_token(p, 28)) // token='!=' ) { - D(fprintf(stderr, "%*c+ _tmp_87[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!='")); + D(fprintf(stderr, "%*c+ _tmp_88[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!='")); _res = _PyPegen_check_barry_as_flufl ( p , tok ) ? NULL : tok; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -29195,7 +30208,7 @@ _tmp_87_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_87[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_88[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!='")); } _res = NULL; @@ -29204,9 +30217,9 @@ _tmp_87_rule(Parser *p) return _res; } -// _loop0_89: ',' (slice | starred_expression) +// _loop0_90: ',' (slice | starred_expression) static asdl_seq * -_loop0_89_rule(Parser *p) +_loop0_90_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29232,13 +30245,13 @@ _loop0_89_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_89[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (slice | starred_expression)")); + D(fprintf(stderr, "%*c> _loop0_90[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (slice | starred_expression)")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_232_rule(p)) // slice | starred_expression + (elem = _tmp_252_rule(p)) // slice | starred_expression ) { _res = elem; @@ -29264,7 +30277,7 @@ _loop0_89_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_89[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_90[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (slice | starred_expression)")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -29281,9 +30294,9 @@ _loop0_89_rule(Parser *p) return _seq; } -// _gather_88: (slice | starred_expression) _loop0_89 +// _gather_89: (slice | starred_expression) _loop0_90 static asdl_seq * -_gather_88_rule(Parser *p) +_gather_89_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29295,27 +30308,27 @@ _gather_88_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (slice | starred_expression) _loop0_89 + { // (slice | starred_expression) _loop0_90 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_89")); + D(fprintf(stderr, "%*c> _gather_89[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_90")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_232_rule(p)) // slice | starred_expression + (elem = _tmp_252_rule(p)) // slice | starred_expression && - (seq = _loop0_89_rule(p)) // _loop0_89 + (seq = _loop0_90_rule(p)) // _loop0_90 ) { - D(fprintf(stderr, "%*c+ _gather_88[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_89")); + D(fprintf(stderr, "%*c+ _gather_89[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_90")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_88[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(slice | starred_expression) _loop0_89")); + D(fprintf(stderr, "%*c%s _gather_89[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(slice | starred_expression) _loop0_90")); } _res = NULL; done: @@ -29323,9 +30336,9 @@ _gather_88_rule(Parser *p) return _res; } -// _tmp_90: ':' expression? +// _tmp_91: ':' expression? static void * -_tmp_90_rule(Parser *p) +_tmp_91_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29342,7 +30355,7 @@ _tmp_90_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_90[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':' expression?")); + D(fprintf(stderr, "%*c> _tmp_91[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':' expression?")); Token * _literal; void *d; if ( @@ -29351,7 +30364,7 @@ _tmp_90_rule(Parser *p) (d = expression_rule(p), !p->error_indicator) // expression? ) { - D(fprintf(stderr, "%*c+ _tmp_90[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' expression?")); + D(fprintf(stderr, "%*c+ _tmp_91[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' expression?")); _res = d; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -29361,7 +30374,7 @@ _tmp_90_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_90[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_91[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':' expression?")); } _res = NULL; @@ -29370,9 +30383,67 @@ _tmp_90_rule(Parser *p) return _res; } -// _tmp_91: tuple | group | genexp +// _tmp_92: STRING | FSTRING_START static void * -_tmp_91_rule(Parser *p) +_tmp_92_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // STRING + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_92[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "STRING")); + expr_ty string_var; + if ( + (string_var = _PyPegen_string_token(p)) // STRING + ) + { + D(fprintf(stderr, "%*c+ _tmp_92[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "STRING")); + _res = string_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_92[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "STRING")); + } + { // FSTRING_START + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_92[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_START")); + Token * fstring_start_var; + if ( + (fstring_start_var = _PyPegen_expect_token(p, FSTRING_START)) // token='FSTRING_START' + ) + { + D(fprintf(stderr, "%*c+ _tmp_92[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_START")); + _res = fstring_start_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_92[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_START")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_93: tuple | group | genexp +static void * +_tmp_93_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29389,18 +30460,18 @@ _tmp_91_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_91[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c> _tmp_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); expr_ty tuple_var; if ( (tuple_var = tuple_rule(p)) // tuple ) { - D(fprintf(stderr, "%*c+ _tmp_91[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c+ _tmp_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); _res = tuple_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_91[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_93[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tuple")); } { // group @@ -29408,18 +30479,18 @@ _tmp_91_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_91[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "group")); + D(fprintf(stderr, "%*c> _tmp_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "group")); expr_ty group_var; if ( (group_var = group_rule(p)) // group ) { - D(fprintf(stderr, "%*c+ _tmp_91[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "group")); + D(fprintf(stderr, "%*c+ _tmp_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "group")); _res = group_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_91[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_93[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "group")); } { // genexp @@ -29427,18 +30498,18 @@ _tmp_91_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_91[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c> _tmp_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); expr_ty genexp_var; if ( (genexp_var = genexp_rule(p)) // genexp ) { - D(fprintf(stderr, "%*c+ _tmp_91[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c+ _tmp_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); _res = genexp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_91[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_93[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "genexp")); } _res = NULL; @@ -29447,9 +30518,9 @@ _tmp_91_rule(Parser *p) return _res; } -// _tmp_92: list | listcomp +// _tmp_94: list | listcomp static void * -_tmp_92_rule(Parser *p) +_tmp_94_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29466,18 +30537,18 @@ _tmp_92_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_92[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c> _tmp_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); expr_ty list_var; if ( (list_var = list_rule(p)) // list ) { - D(fprintf(stderr, "%*c+ _tmp_92[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c+ _tmp_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); _res = list_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_92[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_94[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "list")); } { // listcomp @@ -29485,18 +30556,18 @@ _tmp_92_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_92[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "listcomp")); + D(fprintf(stderr, "%*c> _tmp_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "listcomp")); expr_ty listcomp_var; if ( (listcomp_var = listcomp_rule(p)) // listcomp ) { - D(fprintf(stderr, "%*c+ _tmp_92[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "listcomp")); + D(fprintf(stderr, "%*c+ _tmp_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "listcomp")); _res = listcomp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_92[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_94[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "listcomp")); } _res = NULL; @@ -29505,9 +30576,9 @@ _tmp_92_rule(Parser *p) return _res; } -// _tmp_93: dict | set | dictcomp | setcomp +// _tmp_95: dict | set | dictcomp | setcomp static void * -_tmp_93_rule(Parser *p) +_tmp_95_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29524,18 +30595,18 @@ _tmp_93_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dict")); + D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dict")); expr_ty dict_var; if ( (dict_var = dict_rule(p)) // dict ) { - D(fprintf(stderr, "%*c+ _tmp_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dict")); + D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dict")); _res = dict_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_93[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dict")); } { // set @@ -29543,18 +30614,18 @@ _tmp_93_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "set")); + D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "set")); expr_ty set_var; if ( (set_var = set_rule(p)) // set ) { - D(fprintf(stderr, "%*c+ _tmp_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "set")); + D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "set")); _res = set_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_93[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "set")); } { // dictcomp @@ -29562,18 +30633,18 @@ _tmp_93_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dictcomp")); + D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dictcomp")); expr_ty dictcomp_var; if ( (dictcomp_var = dictcomp_rule(p)) // dictcomp ) { - D(fprintf(stderr, "%*c+ _tmp_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dictcomp")); + D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dictcomp")); _res = dictcomp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_93[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dictcomp")); } { // setcomp @@ -29581,18 +30652,18 @@ _tmp_93_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "setcomp")); + D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "setcomp")); expr_ty setcomp_var; if ( (setcomp_var = setcomp_rule(p)) // setcomp ) { - D(fprintf(stderr, "%*c+ _tmp_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "setcomp")); + D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "setcomp")); _res = setcomp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_93[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "setcomp")); } _res = NULL; @@ -29601,9 +30672,9 @@ _tmp_93_rule(Parser *p) return _res; } -// _tmp_94: yield_expr | named_expression +// _tmp_96: yield_expr | named_expression static void * -_tmp_94_rule(Parser *p) +_tmp_96_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29620,18 +30691,18 @@ _tmp_94_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_94[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_96[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // named_expression @@ -29639,18 +30710,18 @@ _tmp_94_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression")); + D(fprintf(stderr, "%*c> _tmp_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression")); expr_ty named_expression_var; if ( (named_expression_var = named_expression_rule(p)) // named_expression ) { - D(fprintf(stderr, "%*c+ _tmp_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression")); + D(fprintf(stderr, "%*c+ _tmp_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression")); _res = named_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_94[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_96[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "named_expression")); } _res = NULL; @@ -29659,143 +30730,7 @@ _tmp_94_rule(Parser *p) return _res; } -// _loop0_95: lambda_param_no_default -static asdl_seq * -_loop0_95_rule(Parser *p) -{ - if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void *_res = NULL; - int _mark = p->mark; - void **_children = PyMem_Malloc(sizeof(void *)); - if (!_children) { - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - Py_ssize_t _children_capacity = 1; - Py_ssize_t _n = 0; - { // lambda_param_no_default - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _loop0_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); - arg_ty lambda_param_no_default_var; - while ( - (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default - ) - { - _res = lambda_param_no_default_var; - if (_n == _children_capacity) { - _children_capacity *= 2; - void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); - if (!_new_children) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - _children = _new_children; - } - _children[_n++] = _res; - _mark = p->mark; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_95[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); - } - asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); - if (!_seq) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); - PyMem_Free(_children); - p->level--; - return _seq; -} - -// _loop0_96: lambda_param_with_default -static asdl_seq * -_loop0_96_rule(Parser *p) -{ - if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void *_res = NULL; - int _mark = p->mark; - void **_children = PyMem_Malloc(sizeof(void *)); - if (!_children) { - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - Py_ssize_t _children_capacity = 1; - Py_ssize_t _n = 0; - { // lambda_param_with_default - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _loop0_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); - NameDefaultPair* lambda_param_with_default_var; - while ( - (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default - ) - { - _res = lambda_param_with_default_var; - if (_n == _children_capacity) { - _children_capacity *= 2; - void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); - if (!_new_children) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - _children = _new_children; - } - _children[_n++] = _res; - _mark = p->mark; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_96[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); - } - asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); - if (!_seq) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); - PyMem_Free(_children); - p->level--; - return _seq; -} - -// _loop0_97: lambda_param_with_default +// _loop0_97: lambda_param_no_default static asdl_seq * _loop0_97_rule(Parser *p) { @@ -29818,18 +30753,18 @@ _loop0_97_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // lambda_param_with_default + { // lambda_param_no_default if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); - NameDefaultPair* lambda_param_with_default_var; + D(fprintf(stderr, "%*c> _loop0_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + arg_ty lambda_param_no_default_var; while ( - (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default + (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - _res = lambda_param_with_default_var; + _res = lambda_param_no_default_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -29847,7 +30782,7 @@ _loop0_97_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s _loop0_97[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -29863,9 +30798,9 @@ _loop0_97_rule(Parser *p) return _seq; } -// _loop1_98: lambda_param_no_default +// _loop0_98: lambda_param_with_default static asdl_seq * -_loop1_98_rule(Parser *p) +_loop0_98_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29886,18 +30821,18 @@ _loop1_98_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // lambda_param_no_default + { // lambda_param_with_default if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_98[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); - arg_ty lambda_param_no_default_var; + D(fprintf(stderr, "%*c> _loop0_98[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + NameDefaultPair* lambda_param_with_default_var; while ( - (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default + (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default ) { - _res = lambda_param_no_default_var; + _res = lambda_param_with_default_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -29914,13 +30849,8 @@ _loop1_98_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_98[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); - } - if (_n == 0 || p->error_indicator) { - PyMem_Free(_children); - p->level--; - return NULL; + D(fprintf(stderr, "%*c%s _loop0_98[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -30004,7 +30934,7 @@ _loop0_99_rule(Parser *p) return _seq; } -// _loop1_100: lambda_param_with_default +// _loop1_100: lambda_param_no_default static asdl_seq * _loop1_100_rule(Parser *p) { @@ -30027,18 +30957,18 @@ _loop1_100_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // lambda_param_with_default + { // lambda_param_no_default if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_100[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); - NameDefaultPair* lambda_param_with_default_var; + D(fprintf(stderr, "%*c> _loop1_100[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + arg_ty lambda_param_no_default_var; while ( - (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default + (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - _res = lambda_param_with_default_var; + _res = lambda_param_no_default_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30056,7 +30986,7 @@ _loop1_100_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s _loop1_100[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } if (_n == 0 || p->error_indicator) { PyMem_Free(_children); @@ -30077,9 +31007,9 @@ _loop1_100_rule(Parser *p) return _seq; } -// _loop1_101: lambda_param_no_default +// _loop0_101: lambda_param_with_default static asdl_seq * -_loop1_101_rule(Parser *p) +_loop0_101_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30100,18 +31030,18 @@ _loop1_101_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // lambda_param_no_default + { // lambda_param_with_default if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_101[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); - arg_ty lambda_param_no_default_var; + D(fprintf(stderr, "%*c> _loop0_101[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + NameDefaultPair* lambda_param_with_default_var; while ( - (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default + (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default ) { - _res = lambda_param_no_default_var; + _res = lambda_param_with_default_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30128,13 +31058,8 @@ _loop1_101_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_101[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); - } - if (_n == 0 || p->error_indicator) { - PyMem_Free(_children); - p->level--; - return NULL; + D(fprintf(stderr, "%*c%s _loop0_101[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -30150,7 +31075,7 @@ _loop1_101_rule(Parser *p) return _seq; } -// _loop1_102: lambda_param_no_default +// _loop1_102: lambda_param_with_default static asdl_seq * _loop1_102_rule(Parser *p) { @@ -30173,18 +31098,18 @@ _loop1_102_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // lambda_param_no_default + { // lambda_param_with_default if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_102[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); - arg_ty lambda_param_no_default_var; + D(fprintf(stderr, "%*c> _loop1_102[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + NameDefaultPair* lambda_param_with_default_var; while ( - (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default + (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default ) { - _res = lambda_param_no_default_var; + _res = lambda_param_with_default_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30202,7 +31127,7 @@ _loop1_102_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s _loop1_102[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } if (_n == 0 || p->error_indicator) { PyMem_Free(_children); @@ -30223,9 +31148,9 @@ _loop1_102_rule(Parser *p) return _seq; } -// _loop0_103: lambda_param_no_default +// _loop1_103: lambda_param_no_default static asdl_seq * -_loop0_103_rule(Parser *p) +_loop1_103_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30251,7 +31176,7 @@ _loop0_103_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_103[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop1_103[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -30274,9 +31199,14 @@ _loop0_103_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_103[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_103[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } + if (_n == 0 || p->error_indicator) { + PyMem_Free(_children); + p->level--; + return NULL; + } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { PyMem_Free(_children); @@ -30291,7 +31221,7 @@ _loop0_103_rule(Parser *p) return _seq; } -// _loop1_104: lambda_param_with_default +// _loop1_104: lambda_param_no_default static asdl_seq * _loop1_104_rule(Parser *p) { @@ -30314,18 +31244,18 @@ _loop1_104_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // lambda_param_with_default + { // lambda_param_no_default if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_104[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); - NameDefaultPair* lambda_param_with_default_var; + D(fprintf(stderr, "%*c> _loop1_104[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + arg_ty lambda_param_no_default_var; while ( - (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default + (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - _res = lambda_param_with_default_var; + _res = lambda_param_no_default_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30343,7 +31273,7 @@ _loop1_104_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s _loop1_104[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } if (_n == 0 || p->error_indicator) { PyMem_Free(_children); @@ -30505,7 +31435,7 @@ _loop1_106_rule(Parser *p) return _seq; } -// _loop0_107: lambda_param_maybe_default +// _loop0_107: lambda_param_no_default static asdl_seq * _loop0_107_rule(Parser *p) { @@ -30528,18 +31458,18 @@ _loop0_107_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // lambda_param_maybe_default + { // lambda_param_no_default if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_107[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); - NameDefaultPair* lambda_param_maybe_default_var; + D(fprintf(stderr, "%*c> _loop0_107[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + arg_ty lambda_param_no_default_var; while ( - (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default + (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - _res = lambda_param_maybe_default_var; + _res = lambda_param_no_default_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30557,7 +31487,7 @@ _loop0_107_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s _loop0_107[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -30573,7 +31503,7 @@ _loop0_107_rule(Parser *p) return _seq; } -// _loop1_108: lambda_param_maybe_default +// _loop1_108: lambda_param_with_default static asdl_seq * _loop1_108_rule(Parser *p) { @@ -30596,18 +31526,18 @@ _loop1_108_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // lambda_param_maybe_default + { // lambda_param_with_default if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_108[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); - NameDefaultPair* lambda_param_maybe_default_var; + D(fprintf(stderr, "%*c> _loop1_108[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + NameDefaultPair* lambda_param_with_default_var; while ( - (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default + (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default ) { - _res = lambda_param_maybe_default_var; + _res = lambda_param_with_default_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30625,7 +31555,7 @@ _loop1_108_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s _loop1_108[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } if (_n == 0 || p->error_indicator) { PyMem_Free(_children); @@ -30646,9 +31576,9 @@ _loop1_108_rule(Parser *p) return _seq; } -// _loop1_109: STRING +// _loop0_109: lambda_param_maybe_default static asdl_seq * -_loop1_109_rule(Parser *p) +_loop0_109_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30669,18 +31599,18 @@ _loop1_109_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // STRING + { // lambda_param_maybe_default if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_109[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "STRING")); - expr_ty string_var; + D(fprintf(stderr, "%*c> _loop0_109[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + NameDefaultPair* lambda_param_maybe_default_var; while ( - (string_var = _PyPegen_string_token(p)) // STRING + (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default ) { - _res = string_var; + _res = lambda_param_maybe_default_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30697,13 +31627,8 @@ _loop1_109_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_109[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "STRING")); - } - if (_n == 0 || p->error_indicator) { - PyMem_Free(_children); - p->level--; - return NULL; + D(fprintf(stderr, "%*c%s _loop0_109[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -30719,59 +31644,9 @@ _loop1_109_rule(Parser *p) return _seq; } -// _tmp_110: star_named_expression ',' star_named_expressions? -static void * -_tmp_110_rule(Parser *p) -{ - if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // star_named_expression ',' star_named_expressions? - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_110[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); - Token * _literal; - expr_ty y; - void *z; - if ( - (y = star_named_expression_rule(p)) // star_named_expression - && - (_literal = _PyPegen_expect_token(p, 12)) // token=',' - && - (z = star_named_expressions_rule(p), !p->error_indicator) // star_named_expressions? - ) - { - D(fprintf(stderr, "%*c+ _tmp_110[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); - _res = _PyPegen_seq_insert_in_front ( p , y , z ); - if (_res == NULL && PyErr_Occurred()) { - p->error_indicator = 1; - p->level--; - return NULL; - } - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_110[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression ',' star_named_expressions?")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _loop0_112: ',' double_starred_kvpair +// _loop1_110: lambda_param_maybe_default static asdl_seq * -_loop0_112_rule(Parser *p) +_loop1_110_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30792,27 +31667,18 @@ _loop0_112_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // ',' double_starred_kvpair + { // lambda_param_maybe_default if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_112[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); - Token * _literal; - KeyValuePair* elem; + D(fprintf(stderr, "%*c> _loop1_110[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + NameDefaultPair* lambda_param_maybe_default_var; while ( - (_literal = _PyPegen_expect_token(p, 12)) // token=',' - && - (elem = double_starred_kvpair_rule(p)) // double_starred_kvpair + (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default ) { - _res = elem; - if (_res == NULL && PyErr_Occurred()) { - p->error_indicator = 1; - PyMem_Free(_children); - p->level--; - return NULL; - } + _res = lambda_param_maybe_default_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30829,8 +31695,13 @@ _loop0_112_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_112[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' double_starred_kvpair")); + D(fprintf(stderr, "%*c%s _loop1_110[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); + } + if (_n == 0 || p->error_indicator) { + PyMem_Free(_children); + p->level--; + return NULL; } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -30846,9 +31717,9 @@ _loop0_112_rule(Parser *p) return _seq; } -// _gather_111: double_starred_kvpair _loop0_112 -static asdl_seq * -_gather_111_rule(Parser *p) +// _tmp_111: yield_expr | star_expressions +static void * +_tmp_111_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30858,112 +31729,55 @@ _gather_111_rule(Parser *p) p->level--; return NULL; } - asdl_seq * _res = NULL; + void * _res = NULL; int _mark = p->mark; - { // double_starred_kvpair _loop0_112 + { // yield_expr if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_111[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_112")); - KeyValuePair* elem; - asdl_seq * seq; + D(fprintf(stderr, "%*c> _tmp_111[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + expr_ty yield_expr_var; if ( - (elem = double_starred_kvpair_rule(p)) // double_starred_kvpair - && - (seq = _loop0_112_rule(p)) // _loop0_112 + (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _gather_111[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_112")); - _res = _PyPegen_seq_insert_in_front(p, elem, seq); + D(fprintf(stderr, "%*c+ _tmp_111[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_111[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_112")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _loop1_113: for_if_clause -static asdl_seq * -_loop1_113_rule(Parser *p) -{ - if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void *_res = NULL; - int _mark = p->mark; - void **_children = PyMem_Malloc(sizeof(void *)); - if (!_children) { - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; + D(fprintf(stderr, "%*c%s _tmp_111[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } - Py_ssize_t _children_capacity = 1; - Py_ssize_t _n = 0; - { // for_if_clause + { // star_expressions if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause")); - comprehension_ty for_if_clause_var; - while ( - (for_if_clause_var = for_if_clause_rule(p)) // for_if_clause + D(fprintf(stderr, "%*c> _tmp_111[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + expr_ty star_expressions_var; + if ( + (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - _res = for_if_clause_var; - if (_n == _children_capacity) { - _children_capacity *= 2; - void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); - if (!_new_children) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - _children = _new_children; - } - _children[_n++] = _res; - _mark = p->mark; + D(fprintf(stderr, "%*c+ _tmp_111[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + _res = star_expressions_var; + goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_113[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "for_if_clause")); - } - if (_n == 0 || p->error_indicator) { - PyMem_Free(_children); - p->level--; - return NULL; - } - asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); - if (!_seq) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; + D(fprintf(stderr, "%*c%s _tmp_111[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } - for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); - PyMem_Free(_children); + _res = NULL; + done: p->level--; - return _seq; + return _res; } -// _loop0_114: ('if' disjunction) +// _loop0_112: fstring_format_spec static asdl_seq * -_loop0_114_rule(Parser *p) +_loop0_112_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30984,18 +31798,18 @@ _loop0_114_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // ('if' disjunction) + { // fstring_format_spec if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_233_var; + D(fprintf(stderr, "%*c> _loop0_112[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); + expr_ty fstring_format_spec_var; while ( - (_tmp_233_var = _tmp_233_rule(p)) // 'if' disjunction + (fstring_format_spec_var = fstring_format_spec_rule(p)) // fstring_format_spec ) { - _res = _tmp_233_var; + _res = fstring_format_spec_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -31012,8 +31826,8 @@ _loop0_114_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_114[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('if' disjunction)")); + D(fprintf(stderr, "%*c%s _loop0_112[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_format_spec")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -31029,9 +31843,9 @@ _loop0_114_rule(Parser *p) return _seq; } -// _loop0_115: ('if' disjunction) +// _loop1_113: (fstring | string) static asdl_seq * -_loop0_115_rule(Parser *p) +_loop1_113_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31052,18 +31866,18 @@ _loop0_115_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // ('if' disjunction) + { // (fstring | string) if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_234_var; + D(fprintf(stderr, "%*c> _loop1_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(fstring | string)")); + void *_tmp_253_var; while ( - (_tmp_234_var = _tmp_234_rule(p)) // 'if' disjunction + (_tmp_253_var = _tmp_253_rule(p)) // fstring | string ) { - _res = _tmp_234_var; + _res = _tmp_253_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -31080,8 +31894,13 @@ _loop0_115_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_115[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('if' disjunction)")); + D(fprintf(stderr, "%*c%s _loop1_113[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(fstring | string)")); + } + if (_n == 0 || p->error_indicator) { + PyMem_Free(_children); + p->level--; + return NULL; } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -31097,9 +31916,9 @@ _loop0_115_rule(Parser *p) return _seq; } -// _tmp_116: assignment_expression | expression !':=' +// _tmp_114: star_named_expression ',' star_named_expressions? static void * -_tmp_116_rule(Parser *p) +_tmp_114_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31111,45 +31930,35 @@ _tmp_116_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // assignment_expression - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_116[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); - expr_ty assignment_expression_var; - if ( - (assignment_expression_var = assignment_expression_rule(p)) // assignment_expression - ) - { - D(fprintf(stderr, "%*c+ _tmp_116[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); - _res = assignment_expression_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_116[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "assignment_expression")); - } - { // expression !':=' + { // star_named_expression ',' star_named_expressions? if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_116[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); - expr_ty expression_var; + D(fprintf(stderr, "%*c> _tmp_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); + Token * _literal; + expr_ty y; + void *z; if ( - (expression_var = expression_rule(p)) // expression + (y = star_named_expression_rule(p)) // star_named_expression && - _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 53) // token=':=' + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + && + (z = star_named_expressions_rule(p), !p->error_indicator) // star_named_expressions? ) { - D(fprintf(stderr, "%*c+ _tmp_116[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); - _res = expression_var; + D(fprintf(stderr, "%*c+ _tmp_114[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); + _res = _PyPegen_seq_insert_in_front ( p , y , z ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_116[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c%s _tmp_114[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression ',' star_named_expressions?")); } _res = NULL; done: @@ -31157,9 +31966,9 @@ _tmp_116_rule(Parser *p) return _res; } -// _loop0_118: ',' (starred_expression | (assignment_expression | expression !':=') !'=') +// _loop0_116: ',' double_starred_kvpair static asdl_seq * -_loop0_118_rule(Parser *p) +_loop0_116_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31180,18 +31989,18 @@ _loop0_118_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // ',' (starred_expression | (assignment_expression | expression !':=') !'=') + { // ',' double_starred_kvpair if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')")); + D(fprintf(stderr, "%*c> _loop0_116[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); Token * _literal; - void *elem; + KeyValuePair* elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_235_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = double_starred_kvpair_rule(p)) // double_starred_kvpair ) { _res = elem; @@ -31217,8 +32026,8 @@ _loop0_118_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_118[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')")); + D(fprintf(stderr, "%*c%s _loop0_116[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' double_starred_kvpair")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -31234,10 +32043,9 @@ _loop0_118_rule(Parser *p) return _seq; } -// _gather_117: -// | (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_118 +// _gather_115: double_starred_kvpair _loop0_116 static asdl_seq * -_gather_117_rule(Parser *p) +_gather_115_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31249,27 +32057,27 @@ _gather_117_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_118 + { // double_starred_kvpair _loop0_116 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_118")); - void *elem; + D(fprintf(stderr, "%*c> _gather_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_116")); + KeyValuePair* elem; asdl_seq * seq; if ( - (elem = _tmp_235_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = double_starred_kvpair_rule(p)) // double_starred_kvpair && - (seq = _loop0_118_rule(p)) // _loop0_118 + (seq = _loop0_116_rule(p)) // _loop0_116 ) { - D(fprintf(stderr, "%*c+ _gather_117[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_118")); + D(fprintf(stderr, "%*c+ _gather_115[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_116")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_117[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_118")); + D(fprintf(stderr, "%*c%s _gather_115[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_116")); } _res = NULL; done: @@ -31277,9 +32085,9 @@ _gather_117_rule(Parser *p) return _res; } -// _tmp_119: ',' kwargs -static void * -_tmp_119_rule(Parser *p) +// _loop1_117: for_if_clause +static asdl_seq * +_loop1_117_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31289,44 +32097,70 @@ _tmp_119_rule(Parser *p) p->level--; return NULL; } - void * _res = NULL; + void *_res = NULL; int _mark = p->mark; - { // ',' kwargs + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // for_if_clause if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_119[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwargs")); - Token * _literal; - asdl_seq* k; - if ( - (_literal = _PyPegen_expect_token(p, 12)) // token=',' - && - (k = kwargs_rule(p)) // kwargs + D(fprintf(stderr, "%*c> _loop1_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause")); + comprehension_ty for_if_clause_var; + while ( + (for_if_clause_var = for_if_clause_rule(p)) // for_if_clause ) { - D(fprintf(stderr, "%*c+ _tmp_119[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' kwargs")); - _res = k; - if (_res == NULL && PyErr_Occurred()) { - p->error_indicator = 1; - p->level--; - return NULL; + _res = for_if_clause_var; + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; } - goto done; + _children[_n++] = _res; + _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_119[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwargs")); + D(fprintf(stderr, "%*c%s _loop1_117[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "for_if_clause")); } - _res = NULL; - done: + if (_n == 0 || p->error_indicator) { + PyMem_Free(_children); + p->level--; + return NULL; + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); p->level--; - return _res; + return _seq; } -// _loop0_121: ',' kwarg_or_starred +// _loop0_118: ('if' disjunction) static asdl_seq * -_loop0_121_rule(Parser *p) +_loop0_118_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31347,27 +32181,18 @@ _loop0_121_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // ',' kwarg_or_starred + { // ('if' disjunction) if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred")); - Token * _literal; - KeywordOrStarred* elem; + D(fprintf(stderr, "%*c> _loop0_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); + void *_tmp_254_var; while ( - (_literal = _PyPegen_expect_token(p, 12)) // token=',' - && - (elem = kwarg_or_starred_rule(p)) // kwarg_or_starred + (_tmp_254_var = _tmp_254_rule(p)) // 'if' disjunction ) { - _res = elem; - if (_res == NULL && PyErr_Occurred()) { - p->error_indicator = 1; - PyMem_Free(_children); - p->level--; - return NULL; - } + _res = _tmp_254_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -31384,8 +32209,8 @@ _loop0_121_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_121[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_starred")); + D(fprintf(stderr, "%*c%s _loop0_118[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('if' disjunction)")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -31401,9 +32226,9 @@ _loop0_121_rule(Parser *p) return _seq; } -// _gather_120: kwarg_or_starred _loop0_121 +// _loop0_119: ('if' disjunction) static asdl_seq * -_gather_120_rule(Parser *p) +_loop0_119_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31413,29 +32238,115 @@ _gather_120_rule(Parser *p) p->level--; return NULL; } - asdl_seq * _res = NULL; + void *_res = NULL; int _mark = p->mark; - { // kwarg_or_starred _loop0_121 + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // ('if' disjunction) if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_121")); - KeywordOrStarred* elem; - asdl_seq * seq; + D(fprintf(stderr, "%*c> _loop0_119[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); + void *_tmp_255_var; + while ( + (_tmp_255_var = _tmp_255_rule(p)) // 'if' disjunction + ) + { + _res = _tmp_255_var; + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop0_119[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('if' disjunction)")); + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _tmp_120: assignment_expression | expression !':=' +static void * +_tmp_120_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // assignment_expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + expr_ty assignment_expression_var; if ( - (elem = kwarg_or_starred_rule(p)) // kwarg_or_starred + (assignment_expression_var = assignment_expression_rule(p)) // assignment_expression + ) + { + D(fprintf(stderr, "%*c+ _tmp_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + _res = assignment_expression_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_120[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "assignment_expression")); + } + { // expression !':=' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); + expr_ty expression_var; + if ( + (expression_var = expression_rule(p)) // expression && - (seq = _loop0_121_rule(p)) // _loop0_121 + _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 53) // token=':=' ) { - D(fprintf(stderr, "%*c+ _gather_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_121")); - _res = _PyPegen_seq_insert_in_front(p, elem, seq); + D(fprintf(stderr, "%*c+ _tmp_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); + _res = expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_120[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_121")); + D(fprintf(stderr, "%*c%s _tmp_120[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression !':='")); } _res = NULL; done: @@ -31443,9 +32354,9 @@ _gather_120_rule(Parser *p) return _res; } -// _loop0_123: ',' kwarg_or_double_starred +// _loop0_122: ',' (starred_expression | (assignment_expression | expression !':=') !'=') static asdl_seq * -_loop0_123_rule(Parser *p) +_loop0_122_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31466,18 +32377,18 @@ _loop0_123_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // ',' kwarg_or_double_starred + { // ',' (starred_expression | (assignment_expression | expression !':=') !'=') if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_double_starred")); + D(fprintf(stderr, "%*c> _loop0_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')")); Token * _literal; - KeywordOrStarred* elem; + void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_starred + (elem = _tmp_256_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' ) { _res = elem; @@ -31503,8 +32414,8 @@ _loop0_123_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_123[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_double_starred")); + D(fprintf(stderr, "%*c%s _loop0_122[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -31520,9 +32431,10 @@ _loop0_123_rule(Parser *p) return _seq; } -// _gather_122: kwarg_or_double_starred _loop0_123 +// _gather_121: +// | (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_122 static asdl_seq * -_gather_122_rule(Parser *p) +_gather_121_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31534,27 +32446,74 @@ _gather_122_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // kwarg_or_double_starred _loop0_123 + { // (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_122 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_123")); - KeywordOrStarred* elem; + D(fprintf(stderr, "%*c> _gather_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_122")); + void *elem; asdl_seq * seq; if ( - (elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_starred + (elem = _tmp_256_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' && - (seq = _loop0_123_rule(p)) // _loop0_123 + (seq = _loop0_122_rule(p)) // _loop0_122 ) { - D(fprintf(stderr, "%*c+ _gather_122[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_123")); + D(fprintf(stderr, "%*c+ _gather_121[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_122")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_122[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_123")); + D(fprintf(stderr, "%*c%s _gather_121[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_122")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_123: ',' kwargs +static void * +_tmp_123_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // ',' kwargs + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwargs")); + Token * _literal; + asdl_seq* k; + if ( + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + && + (k = kwargs_rule(p)) // kwargs + ) + { + D(fprintf(stderr, "%*c+ _tmp_123[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' kwargs")); + _res = k; + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_123[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwargs")); } _res = NULL; done: @@ -31800,9 +32759,247 @@ _gather_126_rule(Parser *p) return _res; } -// _loop0_128: (',' star_target) +// _loop0_129: ',' kwarg_or_starred static asdl_seq * -_loop0_128_rule(Parser *p) +_loop0_129_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // ',' kwarg_or_starred + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop0_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred")); + Token * _literal; + KeywordOrStarred* elem; + while ( + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + && + (elem = kwarg_or_starred_rule(p)) // kwarg_or_starred + ) + { + _res = elem; + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + PyMem_Free(_children); + p->level--; + return NULL; + } + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop0_129[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_starred")); + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _gather_128: kwarg_or_starred _loop0_129 +static asdl_seq * +_gather_128_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + asdl_seq * _res = NULL; + int _mark = p->mark; + { // kwarg_or_starred _loop0_129 + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _gather_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_129")); + KeywordOrStarred* elem; + asdl_seq * seq; + if ( + (elem = kwarg_or_starred_rule(p)) // kwarg_or_starred + && + (seq = _loop0_129_rule(p)) // _loop0_129 + ) + { + D(fprintf(stderr, "%*c+ _gather_128[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_129")); + _res = _PyPegen_seq_insert_in_front(p, elem, seq); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _gather_128[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_129")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _loop0_131: ',' kwarg_or_double_starred +static asdl_seq * +_loop0_131_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // ',' kwarg_or_double_starred + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop0_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_double_starred")); + Token * _literal; + KeywordOrStarred* elem; + while ( + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + && + (elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_starred + ) + { + _res = elem; + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + PyMem_Free(_children); + p->level--; + return NULL; + } + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop0_131[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_double_starred")); + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _gather_130: kwarg_or_double_starred _loop0_131 +static asdl_seq * +_gather_130_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + asdl_seq * _res = NULL; + int _mark = p->mark; + { // kwarg_or_double_starred _loop0_131 + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _gather_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_131")); + KeywordOrStarred* elem; + asdl_seq * seq; + if ( + (elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_starred + && + (seq = _loop0_131_rule(p)) // _loop0_131 + ) + { + D(fprintf(stderr, "%*c+ _gather_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_131")); + _res = _PyPegen_seq_insert_in_front(p, elem, seq); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _gather_130[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_131")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _loop0_132: (',' star_target) +static asdl_seq * +_loop0_132_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31828,13 +33025,13 @@ _loop0_128_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_236_var; + D(fprintf(stderr, "%*c> _loop0_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); + void *_tmp_257_var; while ( - (_tmp_236_var = _tmp_236_rule(p)) // ',' star_target + (_tmp_257_var = _tmp_257_rule(p)) // ',' star_target ) { - _res = _tmp_236_var; + _res = _tmp_257_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -31851,7 +33048,7 @@ _loop0_128_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_128[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_132[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_target)")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -31868,9 +33065,9 @@ _loop0_128_rule(Parser *p) return _seq; } -// _loop0_130: ',' star_target +// _loop0_134: ',' star_target static asdl_seq * -_loop0_130_rule(Parser *p) +_loop0_134_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31896,7 +33093,7 @@ _loop0_130_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _loop0_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty elem; while ( @@ -31928,7 +33125,7 @@ _loop0_130_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_130[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_134[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -31945,9 +33142,9 @@ _loop0_130_rule(Parser *p) return _seq; } -// _gather_129: star_target _loop0_130 +// _gather_133: star_target _loop0_134 static asdl_seq * -_gather_129_rule(Parser *p) +_gather_133_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31959,27 +33156,27 @@ _gather_129_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // star_target _loop0_130 + { // star_target _loop0_134 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_target _loop0_130")); + D(fprintf(stderr, "%*c> _gather_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_target _loop0_134")); expr_ty elem; asdl_seq * seq; if ( (elem = star_target_rule(p)) // star_target && - (seq = _loop0_130_rule(p)) // _loop0_130 + (seq = _loop0_134_rule(p)) // _loop0_134 ) { - D(fprintf(stderr, "%*c+ _gather_129[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_target _loop0_130")); + D(fprintf(stderr, "%*c+ _gather_133[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_target _loop0_134")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_129[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_target _loop0_130")); + D(fprintf(stderr, "%*c%s _gather_133[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_target _loop0_134")); } _res = NULL; done: @@ -31987,9 +33184,9 @@ _gather_129_rule(Parser *p) return _res; } -// _loop1_131: (',' star_target) +// _loop1_135: (',' star_target) static asdl_seq * -_loop1_131_rule(Parser *p) +_loop1_135_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32015,13 +33212,13 @@ _loop1_131_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_237_var; + D(fprintf(stderr, "%*c> _loop1_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); + void *_tmp_258_var; while ( - (_tmp_237_var = _tmp_237_rule(p)) // ',' star_target + (_tmp_258_var = _tmp_258_rule(p)) // ',' star_target ) { - _res = _tmp_237_var; + _res = _tmp_258_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32038,7 +33235,7 @@ _loop1_131_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_131[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_135[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_target)")); } if (_n == 0 || p->error_indicator) { @@ -32060,9 +33257,9 @@ _loop1_131_rule(Parser *p) return _seq; } -// _tmp_132: !'*' star_target +// _tmp_136: !'*' star_target static void * -_tmp_132_rule(Parser *p) +_tmp_136_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32079,7 +33276,7 @@ _tmp_132_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); + D(fprintf(stderr, "%*c> _tmp_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); expr_ty star_target_var; if ( _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 16) // token='*' @@ -32087,12 +33284,12 @@ _tmp_132_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_132[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); + D(fprintf(stderr, "%*c+ _tmp_136[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); _res = star_target_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_132[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_136[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "!'*' star_target")); } _res = NULL; @@ -32101,9 +33298,9 @@ _tmp_132_rule(Parser *p) return _res; } -// _loop0_134: ',' del_target +// _loop0_138: ',' del_target static asdl_seq * -_loop0_134_rule(Parser *p) +_loop0_138_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32129,7 +33326,7 @@ _loop0_134_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' del_target")); + D(fprintf(stderr, "%*c> _loop0_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' del_target")); Token * _literal; expr_ty elem; while ( @@ -32161,7 +33358,7 @@ _loop0_134_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_134[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_138[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' del_target")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32178,9 +33375,9 @@ _loop0_134_rule(Parser *p) return _seq; } -// _gather_133: del_target _loop0_134 +// _gather_137: del_target _loop0_138 static asdl_seq * -_gather_133_rule(Parser *p) +_gather_137_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32192,27 +33389,27 @@ _gather_133_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // del_target _loop0_134 + { // del_target _loop0_138 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "del_target _loop0_134")); + D(fprintf(stderr, "%*c> _gather_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "del_target _loop0_138")); expr_ty elem; asdl_seq * seq; if ( (elem = del_target_rule(p)) // del_target && - (seq = _loop0_134_rule(p)) // _loop0_134 + (seq = _loop0_138_rule(p)) // _loop0_138 ) { - D(fprintf(stderr, "%*c+ _gather_133[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "del_target _loop0_134")); + D(fprintf(stderr, "%*c+ _gather_137[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "del_target _loop0_138")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_133[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "del_target _loop0_134")); + D(fprintf(stderr, "%*c%s _gather_137[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "del_target _loop0_138")); } _res = NULL; done: @@ -32220,9 +33417,9 @@ _gather_133_rule(Parser *p) return _res; } -// _loop0_136: ',' expression +// _loop0_140: ',' expression static asdl_seq * -_loop0_136_rule(Parser *p) +_loop0_140_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32248,7 +33445,7 @@ _loop0_136_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _loop0_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty elem; while ( @@ -32280,7 +33477,7 @@ _loop0_136_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_136[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_140[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32297,9 +33494,9 @@ _loop0_136_rule(Parser *p) return _seq; } -// _gather_135: expression _loop0_136 +// _gather_139: expression _loop0_140 static asdl_seq * -_gather_135_rule(Parser *p) +_gather_139_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32311,27 +33508,27 @@ _gather_135_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // expression _loop0_136 + { // expression _loop0_140 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_136")); + D(fprintf(stderr, "%*c> _gather_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_140")); expr_ty elem; asdl_seq * seq; if ( (elem = expression_rule(p)) // expression && - (seq = _loop0_136_rule(p)) // _loop0_136 + (seq = _loop0_140_rule(p)) // _loop0_140 ) { - D(fprintf(stderr, "%*c+ _gather_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_136")); + D(fprintf(stderr, "%*c+ _gather_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_140")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_135[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_136")); + D(fprintf(stderr, "%*c%s _gather_139[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_140")); } _res = NULL; done: @@ -32339,9 +33536,9 @@ _gather_135_rule(Parser *p) return _res; } -// _loop0_138: ',' expression +// _loop0_142: ',' expression static asdl_seq * -_loop0_138_rule(Parser *p) +_loop0_142_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32367,7 +33564,7 @@ _loop0_138_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _loop0_142[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty elem; while ( @@ -32399,7 +33596,7 @@ _loop0_138_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_138[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_142[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32416,9 +33613,9 @@ _loop0_138_rule(Parser *p) return _seq; } -// _gather_137: expression _loop0_138 +// _gather_141: expression _loop0_142 static asdl_seq * -_gather_137_rule(Parser *p) +_gather_141_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32430,27 +33627,27 @@ _gather_137_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // expression _loop0_138 + { // expression _loop0_142 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_138")); + D(fprintf(stderr, "%*c> _gather_141[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_142")); expr_ty elem; asdl_seq * seq; if ( (elem = expression_rule(p)) // expression && - (seq = _loop0_138_rule(p)) // _loop0_138 + (seq = _loop0_142_rule(p)) // _loop0_142 ) { - D(fprintf(stderr, "%*c+ _gather_137[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_138")); + D(fprintf(stderr, "%*c+ _gather_141[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_142")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_137[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_138")); + D(fprintf(stderr, "%*c%s _gather_141[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_142")); } _res = NULL; done: @@ -32458,9 +33655,9 @@ _gather_137_rule(Parser *p) return _res; } -// _loop0_140: ',' expression +// _loop0_144: ',' expression static asdl_seq * -_loop0_140_rule(Parser *p) +_loop0_144_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32486,7 +33683,7 @@ _loop0_140_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _loop0_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty elem; while ( @@ -32518,7 +33715,7 @@ _loop0_140_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_140[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_144[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32535,9 +33732,9 @@ _loop0_140_rule(Parser *p) return _seq; } -// _gather_139: expression _loop0_140 +// _gather_143: expression _loop0_144 static asdl_seq * -_gather_139_rule(Parser *p) +_gather_143_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32549,27 +33746,27 @@ _gather_139_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // expression _loop0_140 + { // expression _loop0_144 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_140")); + D(fprintf(stderr, "%*c> _gather_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_144")); expr_ty elem; asdl_seq * seq; if ( (elem = expression_rule(p)) // expression && - (seq = _loop0_140_rule(p)) // _loop0_140 + (seq = _loop0_144_rule(p)) // _loop0_144 ) { - D(fprintf(stderr, "%*c+ _gather_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_140")); + D(fprintf(stderr, "%*c+ _gather_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_144")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_139[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_140")); + D(fprintf(stderr, "%*c%s _gather_143[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_144")); } _res = NULL; done: @@ -32577,9 +33774,9 @@ _gather_139_rule(Parser *p) return _res; } -// _loop0_142: ',' expression +// _loop0_146: ',' expression static asdl_seq * -_loop0_142_rule(Parser *p) +_loop0_146_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32605,7 +33802,7 @@ _loop0_142_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_142[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _loop0_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty elem; while ( @@ -32637,7 +33834,7 @@ _loop0_142_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_142[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_146[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32654,9 +33851,9 @@ _loop0_142_rule(Parser *p) return _seq; } -// _gather_141: expression _loop0_142 +// _gather_145: expression _loop0_146 static asdl_seq * -_gather_141_rule(Parser *p) +_gather_145_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32668,27 +33865,27 @@ _gather_141_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // expression _loop0_142 + { // expression _loop0_146 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_141[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_142")); + D(fprintf(stderr, "%*c> _gather_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_146")); expr_ty elem; asdl_seq * seq; if ( (elem = expression_rule(p)) // expression && - (seq = _loop0_142_rule(p)) // _loop0_142 + (seq = _loop0_146_rule(p)) // _loop0_146 ) { - D(fprintf(stderr, "%*c+ _gather_141[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_142")); + D(fprintf(stderr, "%*c+ _gather_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_146")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_141[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_142")); + D(fprintf(stderr, "%*c%s _gather_145[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_146")); } _res = NULL; done: @@ -32696,9 +33893,9 @@ _gather_141_rule(Parser *p) return _res; } -// _tmp_143: NEWLINE INDENT +// _tmp_147: NEWLINE INDENT static void * -_tmp_143_rule(Parser *p) +_tmp_147_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32715,7 +33912,7 @@ _tmp_143_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); + D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); Token * indent_var; Token * newline_var; if ( @@ -32724,12 +33921,12 @@ _tmp_143_rule(Parser *p) (indent_var = _PyPegen_expect_token(p, INDENT)) // token='INDENT' ) { - D(fprintf(stderr, "%*c+ _tmp_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); + D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); _res = _PyPegen_dummy_name(p, newline_var, indent_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_143[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE INDENT")); } _res = NULL; @@ -32738,9 +33935,9 @@ _tmp_143_rule(Parser *p) return _res; } -// _tmp_144: args | expression for_if_clauses +// _tmp_148: args | expression for_if_clauses static void * -_tmp_144_rule(Parser *p) +_tmp_148_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32757,18 +33954,18 @@ _tmp_144_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args")); + D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args")); expr_ty args_var; if ( (args_var = args_rule(p)) // args ) { - D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args")); + D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args")); _res = args_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_144[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args")); } { // expression for_if_clauses @@ -32776,7 +33973,7 @@ _tmp_144_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); + D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); expr_ty expression_var; asdl_comprehension_seq* for_if_clauses_var; if ( @@ -32785,12 +33982,12 @@ _tmp_144_rule(Parser *p) (for_if_clauses_var = for_if_clauses_rule(p)) // for_if_clauses ) { - D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); + D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); _res = _PyPegen_dummy_name(p, expression_var, for_if_clauses_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_144[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression for_if_clauses")); } _res = NULL; @@ -32799,9 +33996,9 @@ _tmp_144_rule(Parser *p) return _res; } -// _tmp_145: args ',' +// _tmp_149: args ',' static void * -_tmp_145_rule(Parser *p) +_tmp_149_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32818,7 +34015,7 @@ _tmp_145_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ','")); + D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ','")); Token * _literal; expr_ty args_var; if ( @@ -32827,12 +34024,12 @@ _tmp_145_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ','")); + D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ','")); _res = _PyPegen_dummy_name(p, args_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_145[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args ','")); } _res = NULL; @@ -32841,9 +34038,9 @@ _tmp_145_rule(Parser *p) return _res; } -// _tmp_146: ',' | ')' +// _tmp_150: ',' | ')' static void * -_tmp_146_rule(Parser *p) +_tmp_150_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32860,18 +34057,18 @@ _tmp_146_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_146[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_146[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // ')' @@ -32879,18 +34076,18 @@ _tmp_146_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_146[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_146[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } _res = NULL; @@ -32899,9 +34096,9 @@ _tmp_146_rule(Parser *p) return _res; } -// _tmp_147: 'True' | 'False' | 'None' +// _tmp_151: 'True' | 'False' | 'None' static void * -_tmp_147_rule(Parser *p) +_tmp_151_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32918,18 +34115,18 @@ _tmp_147_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 600)) // token='True' + (_keyword = _PyPegen_expect_token(p, 601)) // token='True' ) { - D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'True'")); } { // 'False' @@ -32937,18 +34134,18 @@ _tmp_147_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 602)) // token='False' + (_keyword = _PyPegen_expect_token(p, 603)) // token='False' ) { - D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'False'")); } { // 'None' @@ -32956,18 +34153,18 @@ _tmp_147_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 601)) // token='None' + (_keyword = _PyPegen_expect_token(p, 602)) // token='None' ) { - D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'")); } _res = NULL; @@ -32976,9 +34173,9 @@ _tmp_147_rule(Parser *p) return _res; } -// _tmp_148: NAME '=' +// _tmp_152: NAME '=' static void * -_tmp_148_rule(Parser *p) +_tmp_152_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32995,7 +34192,7 @@ _tmp_148_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME '='")); + D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME '='")); Token * _literal; expr_ty name_var; if ( @@ -33004,12 +34201,12 @@ _tmp_148_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '='")); + D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '='")); _res = _PyPegen_dummy_name(p, name_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME '='")); } _res = NULL; @@ -33018,9 +34215,9 @@ _tmp_148_rule(Parser *p) return _res; } -// _tmp_149: NAME STRING | SOFT_KEYWORD +// _tmp_153: NAME STRING | SOFT_KEYWORD static void * -_tmp_149_rule(Parser *p) +_tmp_153_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33037,7 +34234,7 @@ _tmp_149_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME STRING")); + D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME STRING")); expr_ty name_var; expr_ty string_var; if ( @@ -33046,12 +34243,12 @@ _tmp_149_rule(Parser *p) (string_var = _PyPegen_string_token(p)) // STRING ) { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME STRING")); + D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME STRING")); _res = _PyPegen_dummy_name(p, name_var, string_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME STRING")); } { // SOFT_KEYWORD @@ -33059,18 +34256,18 @@ _tmp_149_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); + D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); expr_ty soft_keyword_var; if ( (soft_keyword_var = _PyPegen_soft_keyword_token(p)) // SOFT_KEYWORD ) { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); + D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); _res = soft_keyword_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "SOFT_KEYWORD")); } _res = NULL; @@ -33079,9 +34276,9 @@ _tmp_149_rule(Parser *p) return _res; } -// _tmp_150: 'else' | ':' +// _tmp_154: 'else' | ':' static void * -_tmp_150_rule(Parser *p) +_tmp_154_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33098,18 +34295,18 @@ _tmp_150_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'else'")); + D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'else'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 644)) // token='else' + (_keyword = _PyPegen_expect_token(p, 645)) // token='else' ) { - D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else'")); + D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'else'")); } { // ':' @@ -33117,18 +34314,18 @@ _tmp_150_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -33137,9 +34334,67 @@ _tmp_150_rule(Parser *p) return _res; } -// _tmp_151: '=' | ':=' +// _tmp_155: FSTRING_MIDDLE | fstring_replacement_field static void * -_tmp_151_rule(Parser *p) +_tmp_155_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // FSTRING_MIDDLE + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE")); + Token * fstring_middle_var; + if ( + (fstring_middle_var = _PyPegen_expect_token(p, FSTRING_MIDDLE)) // token='FSTRING_MIDDLE' + ) + { + D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE")); + _res = fstring_middle_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_MIDDLE")); + } + { // fstring_replacement_field + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field")); + expr_ty fstring_replacement_field_var; + if ( + (fstring_replacement_field_var = fstring_replacement_field_rule(p)) // fstring_replacement_field + ) + { + D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field")); + _res = fstring_replacement_field_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_replacement_field")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_156: '=' | ':=' +static void * +_tmp_156_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33156,18 +34411,18 @@ _tmp_151_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } { // ':=' @@ -33175,18 +34430,18 @@ _tmp_151_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 53)) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':='")); } _res = NULL; @@ -33195,9 +34450,9 @@ _tmp_151_rule(Parser *p) return _res; } -// _tmp_152: list | tuple | genexp | 'True' | 'None' | 'False' +// _tmp_157: list | tuple | genexp | 'True' | 'None' | 'False' static void * -_tmp_152_rule(Parser *p) +_tmp_157_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33214,18 +34469,18 @@ _tmp_152_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); expr_ty list_var; if ( (list_var = list_rule(p)) // list ) { - D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); _res = list_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "list")); } { // tuple @@ -33233,18 +34488,18 @@ _tmp_152_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); expr_ty tuple_var; if ( (tuple_var = tuple_rule(p)) // tuple ) { - D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); _res = tuple_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tuple")); } { // genexp @@ -33252,18 +34507,18 @@ _tmp_152_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); expr_ty genexp_var; if ( (genexp_var = genexp_rule(p)) // genexp ) { - D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); _res = genexp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "genexp")); } { // 'True' @@ -33271,18 +34526,18 @@ _tmp_152_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 600)) // token='True' + (_keyword = _PyPegen_expect_token(p, 601)) // token='True' ) { - D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'True'")); } { // 'None' @@ -33290,18 +34545,18 @@ _tmp_152_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 601)) // token='None' + (_keyword = _PyPegen_expect_token(p, 602)) // token='None' ) { - D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'")); } { // 'False' @@ -33309,18 +34564,18 @@ _tmp_152_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 602)) // token='False' + (_keyword = _PyPegen_expect_token(p, 603)) // token='False' ) { - D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'False'")); } _res = NULL; @@ -33329,9 +34584,9 @@ _tmp_152_rule(Parser *p) return _res; } -// _tmp_153: '=' | ':=' +// _tmp_158: '=' | ':=' static void * -_tmp_153_rule(Parser *p) +_tmp_158_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33348,18 +34603,18 @@ _tmp_153_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } { // ':=' @@ -33367,18 +34622,18 @@ _tmp_153_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 53)) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':='")); } _res = NULL; @@ -33387,9 +34642,9 @@ _tmp_153_rule(Parser *p) return _res; } -// _loop0_154: star_named_expressions +// _loop0_159: star_named_expressions static asdl_seq * -_loop0_154_rule(Parser *p) +_loop0_159_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33415,7 +34670,7 @@ _loop0_154_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions")); + D(fprintf(stderr, "%*c> _loop0_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions")); asdl_expr_seq* star_named_expressions_var; while ( (star_named_expressions_var = star_named_expressions_rule(p)) // star_named_expressions @@ -33438,7 +34693,7 @@ _loop0_154_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_154[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expressions")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33455,9 +34710,9 @@ _loop0_154_rule(Parser *p) return _seq; } -// _loop0_155: (star_targets '=') +// _loop0_160: (star_targets '=') static asdl_seq * -_loop0_155_rule(Parser *p) +_loop0_160_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33483,13 +34738,13 @@ _loop0_155_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_238_var; + D(fprintf(stderr, "%*c> _loop0_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); + void *_tmp_259_var; while ( - (_tmp_238_var = _tmp_238_rule(p)) // star_targets '=' + (_tmp_259_var = _tmp_259_rule(p)) // star_targets '=' ) { - _res = _tmp_238_var; + _res = _tmp_259_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -33506,7 +34761,7 @@ _loop0_155_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_155[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_160[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33523,9 +34778,9 @@ _loop0_155_rule(Parser *p) return _seq; } -// _loop0_156: (star_targets '=') +// _loop0_161: (star_targets '=') static asdl_seq * -_loop0_156_rule(Parser *p) +_loop0_161_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33551,13 +34806,13 @@ _loop0_156_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_239_var; + D(fprintf(stderr, "%*c> _loop0_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); + void *_tmp_260_var; while ( - (_tmp_239_var = _tmp_239_rule(p)) // star_targets '=' + (_tmp_260_var = _tmp_260_rule(p)) // star_targets '=' ) { - _res = _tmp_239_var; + _res = _tmp_260_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -33574,7 +34829,7 @@ _loop0_156_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_156[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_161[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33591,9 +34846,9 @@ _loop0_156_rule(Parser *p) return _seq; } -// _tmp_157: yield_expr | star_expressions +// _tmp_162: yield_expr | star_expressions static void * -_tmp_157_rule(Parser *p) +_tmp_162_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33610,18 +34865,18 @@ _tmp_157_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_162[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_162[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -33629,18 +34884,18 @@ _tmp_157_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_162[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_162[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -33649,9 +34904,9 @@ _tmp_157_rule(Parser *p) return _res; } -// _tmp_158: '[' | '(' | '{' +// _tmp_163: '[' | '(' | '{' static void * -_tmp_158_rule(Parser *p) +_tmp_163_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33668,18 +34923,18 @@ _tmp_158_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); } { // '(' @@ -33687,18 +34942,18 @@ _tmp_158_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); + D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('")); } { // '{' @@ -33706,18 +34961,18 @@ _tmp_158_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); } _res = NULL; @@ -33726,9 +34981,9 @@ _tmp_158_rule(Parser *p) return _res; } -// _tmp_159: '[' | '{' +// _tmp_164: '[' | '{' static void * -_tmp_159_rule(Parser *p) +_tmp_164_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33745,18 +35000,18 @@ _tmp_159_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' ) { - D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); } { // '{' @@ -33764,18 +35019,18 @@ _tmp_159_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' ) { - D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); } _res = NULL; @@ -33784,9 +35039,9 @@ _tmp_159_rule(Parser *p) return _res; } -// _tmp_160: '[' | '{' +// _tmp_165: '[' | '{' static void * -_tmp_160_rule(Parser *p) +_tmp_165_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33803,18 +35058,18 @@ _tmp_160_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' ) { - D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); } { // '{' @@ -33822,18 +35077,18 @@ _tmp_160_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' ) { - D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); } _res = NULL; @@ -33842,9 +35097,9 @@ _tmp_160_rule(Parser *p) return _res; } -// _tmp_161: slash_no_default | slash_with_default +// _tmp_166: slash_no_default | slash_with_default static void * -_tmp_161_rule(Parser *p) +_tmp_166_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33861,18 +35116,18 @@ _tmp_161_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); asdl_arg_seq* slash_no_default_var; if ( (slash_no_default_var = slash_no_default_rule(p)) // slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_161[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); _res = slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_161[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_no_default")); } { // slash_with_default @@ -33880,18 +35135,18 @@ _tmp_161_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); SlashWithDefault* slash_with_default_var; if ( (slash_with_default_var = slash_with_default_rule(p)) // slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_161[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); _res = slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_161[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_with_default")); } _res = NULL; @@ -33900,9 +35155,9 @@ _tmp_161_rule(Parser *p) return _res; } -// _loop0_162: param_maybe_default +// _loop0_167: param_maybe_default static asdl_seq * -_loop0_162_rule(Parser *p) +_loop0_167_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33928,7 +35183,7 @@ _loop0_162_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -33951,7 +35206,7 @@ _loop0_162_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_162[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_167[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33968,9 +35223,9 @@ _loop0_162_rule(Parser *p) return _seq; } -// _loop0_163: param_no_default +// _loop0_168: param_no_default static asdl_seq * -_loop0_163_rule(Parser *p) +_loop0_168_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33996,7 +35251,7 @@ _loop0_163_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop0_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -34019,7 +35274,7 @@ _loop0_163_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_163[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_168[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -34036,9 +35291,9 @@ _loop0_163_rule(Parser *p) return _seq; } -// _loop0_164: param_no_default +// _loop0_169: param_no_default static asdl_seq * -_loop0_164_rule(Parser *p) +_loop0_169_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34064,7 +35319,7 @@ _loop0_164_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop0_169[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -34087,7 +35342,7 @@ _loop0_164_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_164[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_169[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -34104,9 +35359,9 @@ _loop0_164_rule(Parser *p) return _seq; } -// _loop1_165: param_no_default +// _loop1_170: param_no_default static asdl_seq * -_loop1_165_rule(Parser *p) +_loop1_170_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34132,7 +35387,7 @@ _loop1_165_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop1_170[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; while ( (param_no_default_var = param_no_default_rule(p)) // param_no_default @@ -34155,7 +35410,7 @@ _loop1_165_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_165[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_170[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -34177,9 +35432,9 @@ _loop1_165_rule(Parser *p) return _seq; } -// _tmp_166: slash_no_default | slash_with_default +// _tmp_171: slash_no_default | slash_with_default static void * -_tmp_166_rule(Parser *p) +_tmp_171_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34196,18 +35451,18 @@ _tmp_166_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); asdl_arg_seq* slash_no_default_var; if ( (slash_no_default_var = slash_no_default_rule(p)) // slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_171[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); _res = slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_171[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_no_default")); } { // slash_with_default @@ -34215,18 +35470,18 @@ _tmp_166_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); SlashWithDefault* slash_with_default_var; if ( (slash_with_default_var = slash_with_default_rule(p)) // slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_171[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); _res = slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_171[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_with_default")); } _res = NULL; @@ -34235,9 +35490,9 @@ _tmp_166_rule(Parser *p) return _res; } -// _loop0_167: param_maybe_default +// _loop0_172: param_maybe_default static asdl_seq * -_loop0_167_rule(Parser *p) +_loop0_172_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34263,7 +35518,7 @@ _loop0_167_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -34286,7 +35541,7 @@ _loop0_167_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_167[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_172[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -34303,9 +35558,9 @@ _loop0_167_rule(Parser *p) return _seq; } -// _tmp_168: ',' | param_no_default +// _tmp_173: ',' | param_no_default static void * -_tmp_168_rule(Parser *p) +_tmp_173_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34322,18 +35577,18 @@ _tmp_168_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_168[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_168[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // param_no_default @@ -34341,18 +35596,18 @@ _tmp_168_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; if ( (param_no_default_var = param_no_default_rule(p)) // param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_168[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); _res = param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_168[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } _res = NULL; @@ -34361,9 +35616,9 @@ _tmp_168_rule(Parser *p) return _res; } -// _loop0_169: param_maybe_default +// _loop0_174: param_maybe_default static asdl_seq * -_loop0_169_rule(Parser *p) +_loop0_174_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34389,7 +35644,7 @@ _loop0_169_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_169[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_174[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -34412,7 +35667,7 @@ _loop0_169_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_169[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_174[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -34429,9 +35684,9 @@ _loop0_169_rule(Parser *p) return _seq; } -// _loop1_170: param_maybe_default +// _loop1_175: param_maybe_default static asdl_seq * -_loop1_170_rule(Parser *p) +_loop1_175_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34457,7 +35712,7 @@ _loop1_170_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_170[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop1_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -34480,7 +35735,7 @@ _loop1_170_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_170[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_175[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } if (_n == 0 || p->error_indicator) { @@ -34502,9 +35757,9 @@ _loop1_170_rule(Parser *p) return _seq; } -// _tmp_171: ')' | ',' +// _tmp_176: ')' | ',' static void * -_tmp_171_rule(Parser *p) +_tmp_176_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34521,18 +35776,18 @@ _tmp_171_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_176[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_171[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_176[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_171[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_176[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ',' @@ -34540,18 +35795,18 @@ _tmp_171_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_176[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_171[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_176[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_171[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_176[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -34560,9 +35815,9 @@ _tmp_171_rule(Parser *p) return _res; } -// _tmp_172: ')' | ',' (')' | '**') +// _tmp_177: ')' | ',' (')' | '**') static void * -_tmp_172_rule(Parser *p) +_tmp_177_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34579,18 +35834,18 @@ _tmp_172_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_172[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_177[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_172[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_177[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ',' (')' | '**') @@ -34598,21 +35853,21 @@ _tmp_172_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); + D(fprintf(stderr, "%*c> _tmp_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); Token * _literal; - void *_tmp_240_var; + void *_tmp_261_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_240_var = _tmp_240_rule(p)) // ')' | '**' + (_tmp_261_var = _tmp_261_rule(p)) // ')' | '**' ) { - D(fprintf(stderr, "%*c+ _tmp_172[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_240_var); + D(fprintf(stderr, "%*c+ _tmp_177[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_261_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_172[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_177[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (')' | '**')")); } _res = NULL; @@ -34621,9 +35876,9 @@ _tmp_172_rule(Parser *p) return _res; } -// _tmp_173: param_no_default | ',' +// _tmp_178: param_no_default | ',' static void * -_tmp_173_rule(Parser *p) +_tmp_178_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34640,18 +35895,18 @@ _tmp_173_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; if ( (param_no_default_var = param_no_default_rule(p)) // param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); _res = param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } { // ',' @@ -34659,18 +35914,18 @@ _tmp_173_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -34679,9 +35934,9 @@ _tmp_173_rule(Parser *p) return _res; } -// _loop0_174: param_maybe_default +// _loop0_179: param_maybe_default static asdl_seq * -_loop0_174_rule(Parser *p) +_loop0_179_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34707,7 +35962,7 @@ _loop0_174_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_174[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); NameDefaultPair* param_maybe_default_var; while ( (param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default @@ -34730,7 +35985,7 @@ _loop0_174_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_174[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_179[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -34747,9 +36002,9 @@ _loop0_174_rule(Parser *p) return _seq; } -// _tmp_175: param_no_default | ',' +// _tmp_180: param_no_default | ',' static void * -_tmp_175_rule(Parser *p) +_tmp_180_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34766,18 +36021,18 @@ _tmp_175_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _tmp_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; if ( (param_no_default_var = param_no_default_rule(p)) // param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_175[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_180[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); _res = param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_175[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_180[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } { // ',' @@ -34785,18 +36040,18 @@ _tmp_175_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_175[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_180[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_175[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_180[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -34805,9 +36060,9 @@ _tmp_175_rule(Parser *p) return _res; } -// _tmp_176: '*' | '**' | '/' +// _tmp_181: '*' | '**' | '/' static void * -_tmp_176_rule(Parser *p) +_tmp_181_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34824,18 +36079,18 @@ _tmp_176_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_176[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c> _tmp_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' ) { - D(fprintf(stderr, "%*c+ _tmp_176[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c+ _tmp_181[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_176[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_181[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*'")); } { // '**' @@ -34843,18 +36098,18 @@ _tmp_176_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_176[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_176[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_181[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_176[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_181[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } { // '/' @@ -34862,18 +36117,18 @@ _tmp_176_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_176[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c> _tmp_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 17)) // token='/' ) { - D(fprintf(stderr, "%*c+ _tmp_176[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c+ _tmp_181[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_176[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_181[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'/'")); } _res = NULL; @@ -34882,9 +36137,9 @@ _tmp_176_rule(Parser *p) return _res; } -// _loop1_177: param_with_default +// _loop1_182: param_with_default static asdl_seq * -_loop1_177_rule(Parser *p) +_loop1_182_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34910,7 +36165,7 @@ _loop1_177_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop1_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); NameDefaultPair* param_with_default_var; while ( (param_with_default_var = param_with_default_rule(p)) // param_with_default @@ -34933,7 +36188,7 @@ _loop1_177_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_177[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_182[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -34955,9 +36210,9 @@ _loop1_177_rule(Parser *p) return _seq; } -// _tmp_178: lambda_slash_no_default | lambda_slash_with_default +// _tmp_183: lambda_slash_no_default | lambda_slash_with_default static void * -_tmp_178_rule(Parser *p) +_tmp_183_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34974,18 +36229,18 @@ _tmp_178_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); asdl_arg_seq* lambda_slash_no_default_var; if ( (lambda_slash_no_default_var = lambda_slash_no_default_rule(p)) // lambda_slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_183[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); _res = lambda_slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_183[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_no_default")); } { // lambda_slash_with_default @@ -34993,18 +36248,18 @@ _tmp_178_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); SlashWithDefault* lambda_slash_with_default_var; if ( (lambda_slash_with_default_var = lambda_slash_with_default_rule(p)) // lambda_slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_183[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); _res = lambda_slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_183[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_with_default")); } _res = NULL; @@ -35013,9 +36268,9 @@ _tmp_178_rule(Parser *p) return _res; } -// _loop0_179: lambda_param_maybe_default +// _loop0_184: lambda_param_maybe_default static asdl_seq * -_loop0_179_rule(Parser *p) +_loop0_184_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35041,7 +36296,7 @@ _loop0_179_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_184[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -35064,7 +36319,7 @@ _loop0_179_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_179[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_184[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35081,9 +36336,9 @@ _loop0_179_rule(Parser *p) return _seq; } -// _loop0_180: lambda_param_no_default +// _loop0_185: lambda_param_no_default static asdl_seq * -_loop0_180_rule(Parser *p) +_loop0_185_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35109,7 +36364,7 @@ _loop0_180_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_185[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -35132,7 +36387,7 @@ _loop0_180_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_180[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_185[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35149,9 +36404,9 @@ _loop0_180_rule(Parser *p) return _seq; } -// _loop0_181: lambda_param_no_default +// _loop0_186: lambda_param_no_default static asdl_seq * -_loop0_181_rule(Parser *p) +_loop0_186_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35177,7 +36432,7 @@ _loop0_181_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_186[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -35200,7 +36455,7 @@ _loop0_181_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_181[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_186[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35217,9 +36472,9 @@ _loop0_181_rule(Parser *p) return _seq; } -// _loop0_183: ',' lambda_param +// _loop0_188: ',' lambda_param static asdl_seq * -_loop0_183_rule(Parser *p) +_loop0_188_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35245,7 +36500,7 @@ _loop0_183_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' lambda_param")); + D(fprintf(stderr, "%*c> _loop0_188[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' lambda_param")); Token * _literal; arg_ty elem; while ( @@ -35277,7 +36532,7 @@ _loop0_183_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_183[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_188[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' lambda_param")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35294,9 +36549,9 @@ _loop0_183_rule(Parser *p) return _seq; } -// _gather_182: lambda_param _loop0_183 +// _gather_187: lambda_param _loop0_188 static asdl_seq * -_gather_182_rule(Parser *p) +_gather_187_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35308,27 +36563,27 @@ _gather_182_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // lambda_param _loop0_183 + { // lambda_param _loop0_188 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_183")); + D(fprintf(stderr, "%*c> _gather_187[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_188")); arg_ty elem; asdl_seq * seq; if ( (elem = lambda_param_rule(p)) // lambda_param && - (seq = _loop0_183_rule(p)) // _loop0_183 + (seq = _loop0_188_rule(p)) // _loop0_188 ) { - D(fprintf(stderr, "%*c+ _gather_182[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_183")); + D(fprintf(stderr, "%*c+ _gather_187[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_188")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_182[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param _loop0_183")); + D(fprintf(stderr, "%*c%s _gather_187[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param _loop0_188")); } _res = NULL; done: @@ -35336,9 +36591,9 @@ _gather_182_rule(Parser *p) return _res; } -// _tmp_184: lambda_slash_no_default | lambda_slash_with_default +// _tmp_189: lambda_slash_no_default | lambda_slash_with_default static void * -_tmp_184_rule(Parser *p) +_tmp_189_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35355,18 +36610,18 @@ _tmp_184_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_184[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_189[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); asdl_arg_seq* lambda_slash_no_default_var; if ( (lambda_slash_no_default_var = lambda_slash_no_default_rule(p)) // lambda_slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_184[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_189[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); _res = lambda_slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_184[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_189[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_no_default")); } { // lambda_slash_with_default @@ -35374,18 +36629,18 @@ _tmp_184_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_184[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_189[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); SlashWithDefault* lambda_slash_with_default_var; if ( (lambda_slash_with_default_var = lambda_slash_with_default_rule(p)) // lambda_slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_184[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_189[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); _res = lambda_slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_184[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_189[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_with_default")); } _res = NULL; @@ -35394,9 +36649,9 @@ _tmp_184_rule(Parser *p) return _res; } -// _loop0_185: lambda_param_maybe_default +// _loop0_190: lambda_param_maybe_default static asdl_seq * -_loop0_185_rule(Parser *p) +_loop0_190_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35422,7 +36677,7 @@ _loop0_185_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_185[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_190[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -35445,7 +36700,7 @@ _loop0_185_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_185[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_190[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35462,9 +36717,9 @@ _loop0_185_rule(Parser *p) return _seq; } -// _tmp_186: ',' | lambda_param_no_default +// _tmp_191: ',' | lambda_param_no_default static void * -_tmp_186_rule(Parser *p) +_tmp_191_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35481,18 +36736,18 @@ _tmp_186_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_186[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_191[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_186[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_191[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_186[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_191[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // lambda_param_no_default @@ -35500,18 +36755,18 @@ _tmp_186_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_186[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _tmp_191[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; if ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_186[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_191[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); _res = lambda_param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_186[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_191[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } _res = NULL; @@ -35520,9 +36775,9 @@ _tmp_186_rule(Parser *p) return _res; } -// _loop0_187: lambda_param_maybe_default +// _loop0_192: lambda_param_maybe_default static asdl_seq * -_loop0_187_rule(Parser *p) +_loop0_192_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35548,7 +36803,7 @@ _loop0_187_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_187[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_192[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -35571,7 +36826,7 @@ _loop0_187_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_187[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_192[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35588,9 +36843,9 @@ _loop0_187_rule(Parser *p) return _seq; } -// _loop1_188: lambda_param_maybe_default +// _loop1_193: lambda_param_maybe_default static asdl_seq * -_loop1_188_rule(Parser *p) +_loop1_193_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35616,7 +36871,7 @@ _loop1_188_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_188[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop1_193[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -35639,7 +36894,7 @@ _loop1_188_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_188[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_193[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } if (_n == 0 || p->error_indicator) { @@ -35661,9 +36916,9 @@ _loop1_188_rule(Parser *p) return _seq; } -// _loop1_189: lambda_param_with_default +// _loop1_194: lambda_param_with_default static asdl_seq * -_loop1_189_rule(Parser *p) +_loop1_194_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35689,7 +36944,7 @@ _loop1_189_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_189[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop1_194[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -35712,7 +36967,7 @@ _loop1_189_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_189[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_194[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -35734,9 +36989,9 @@ _loop1_189_rule(Parser *p) return _seq; } -// _tmp_190: ':' | ',' (':' | '**') +// _tmp_195: ':' | ',' (':' | '**') static void * -_tmp_190_rule(Parser *p) +_tmp_195_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35753,18 +37008,18 @@ _tmp_190_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_190[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_195[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_190[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_195[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_190[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_195[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // ',' (':' | '**') @@ -35772,21 +37027,21 @@ _tmp_190_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_190[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); + D(fprintf(stderr, "%*c> _tmp_195[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); Token * _literal; - void *_tmp_241_var; + void *_tmp_262_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_241_var = _tmp_241_rule(p)) // ':' | '**' + (_tmp_262_var = _tmp_262_rule(p)) // ':' | '**' ) { - D(fprintf(stderr, "%*c+ _tmp_190[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_241_var); + D(fprintf(stderr, "%*c+ _tmp_195[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_262_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_190[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_195[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (':' | '**')")); } _res = NULL; @@ -35795,9 +37050,9 @@ _tmp_190_rule(Parser *p) return _res; } -// _tmp_191: lambda_param_no_default | ',' +// _tmp_196: lambda_param_no_default | ',' static void * -_tmp_191_rule(Parser *p) +_tmp_196_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35814,18 +37069,18 @@ _tmp_191_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_191[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _tmp_196[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; if ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_191[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_196[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); _res = lambda_param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_191[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_196[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } { // ',' @@ -35833,18 +37088,18 @@ _tmp_191_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_191[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_196[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_191[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_196[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_191[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_196[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -35853,9 +37108,9 @@ _tmp_191_rule(Parser *p) return _res; } -// _loop0_192: lambda_param_maybe_default +// _loop0_197: lambda_param_maybe_default static asdl_seq * -_loop0_192_rule(Parser *p) +_loop0_197_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35881,7 +37136,7 @@ _loop0_192_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_192[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -35904,7 +37159,7 @@ _loop0_192_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_192[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_197[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35921,9 +37176,9 @@ _loop0_192_rule(Parser *p) return _seq; } -// _tmp_193: lambda_param_no_default | ',' +// _tmp_198: lambda_param_no_default | ',' static void * -_tmp_193_rule(Parser *p) +_tmp_198_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35940,18 +37195,18 @@ _tmp_193_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_193[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _tmp_198[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; if ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_193[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_198[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); _res = lambda_param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_193[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_198[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } { // ',' @@ -35959,18 +37214,18 @@ _tmp_193_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_193[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_198[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_193[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_198[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_193[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_198[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -35979,9 +37234,9 @@ _tmp_193_rule(Parser *p) return _res; } -// _tmp_194: '*' | '**' | '/' +// _tmp_199: '*' | '**' | '/' static void * -_tmp_194_rule(Parser *p) +_tmp_199_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35998,18 +37253,18 @@ _tmp_194_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_194[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c> _tmp_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' ) { - D(fprintf(stderr, "%*c+ _tmp_194[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c+ _tmp_199[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_194[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_199[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*'")); } { // '**' @@ -36017,18 +37272,18 @@ _tmp_194_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_194[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_194[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_199[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_194[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_199[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } { // '/' @@ -36036,18 +37291,18 @@ _tmp_194_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_194[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c> _tmp_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 17)) // token='/' ) { - D(fprintf(stderr, "%*c+ _tmp_194[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c+ _tmp_199[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_194[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_199[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'/'")); } _res = NULL; @@ -36056,9 +37311,9 @@ _tmp_194_rule(Parser *p) return _res; } -// _tmp_195: ',' | ')' | ':' +// _tmp_200: ',' | ')' | ':' static void * -_tmp_195_rule(Parser *p) +_tmp_200_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36075,18 +37330,18 @@ _tmp_195_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_195[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_195[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_195[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // ')' @@ -36094,18 +37349,18 @@ _tmp_195_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_195[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_195[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_195[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ':' @@ -36113,18 +37368,18 @@ _tmp_195_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_195[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_195[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_195[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -36133,9 +37388,9 @@ _tmp_195_rule(Parser *p) return _res; } -// _loop0_197: ',' (expression ['as' star_target]) +// _loop0_202: ',' (expression ['as' star_target]) static asdl_seq * -_loop0_197_rule(Parser *p) +_loop0_202_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36161,13 +37416,13 @@ _loop0_197_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_242_rule(p)) // expression ['as' star_target] + (elem = _tmp_263_rule(p)) // expression ['as' star_target] ) { _res = elem; @@ -36193,7 +37448,7 @@ _loop0_197_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_197[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_202[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36210,9 +37465,9 @@ _loop0_197_rule(Parser *p) return _seq; } -// _gather_196: (expression ['as' star_target]) _loop0_197 +// _gather_201: (expression ['as' star_target]) _loop0_202 static asdl_seq * -_gather_196_rule(Parser *p) +_gather_201_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36224,27 +37479,27 @@ _gather_196_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expression ['as' star_target]) _loop0_197 + { // (expression ['as' star_target]) _loop0_202 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_196[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_197")); + D(fprintf(stderr, "%*c> _gather_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_202")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_242_rule(p)) // expression ['as' star_target] + (elem = _tmp_263_rule(p)) // expression ['as' star_target] && - (seq = _loop0_197_rule(p)) // _loop0_197 + (seq = _loop0_202_rule(p)) // _loop0_202 ) { - D(fprintf(stderr, "%*c+ _gather_196[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_197")); + D(fprintf(stderr, "%*c+ _gather_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_202")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_196[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_197")); + D(fprintf(stderr, "%*c%s _gather_201[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_202")); } _res = NULL; done: @@ -36252,9 +37507,9 @@ _gather_196_rule(Parser *p) return _res; } -// _loop0_199: ',' (expressions ['as' star_target]) +// _loop0_204: ',' (expressions ['as' star_target]) static asdl_seq * -_loop0_199_rule(Parser *p) +_loop0_204_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36280,13 +37535,13 @@ _loop0_199_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_204[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_243_rule(p)) // expressions ['as' star_target] + (elem = _tmp_264_rule(p)) // expressions ['as' star_target] ) { _res = elem; @@ -36312,7 +37567,7 @@ _loop0_199_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_199[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_204[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36329,9 +37584,9 @@ _loop0_199_rule(Parser *p) return _seq; } -// _gather_198: (expressions ['as' star_target]) _loop0_199 +// _gather_203: (expressions ['as' star_target]) _loop0_204 static asdl_seq * -_gather_198_rule(Parser *p) +_gather_203_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36343,27 +37598,27 @@ _gather_198_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expressions ['as' star_target]) _loop0_199 + { // (expressions ['as' star_target]) _loop0_204 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_198[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_199")); + D(fprintf(stderr, "%*c> _gather_203[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_204")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_243_rule(p)) // expressions ['as' star_target] + (elem = _tmp_264_rule(p)) // expressions ['as' star_target] && - (seq = _loop0_199_rule(p)) // _loop0_199 + (seq = _loop0_204_rule(p)) // _loop0_204 ) { - D(fprintf(stderr, "%*c+ _gather_198[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_199")); + D(fprintf(stderr, "%*c+ _gather_203[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_204")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_198[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_199")); + D(fprintf(stderr, "%*c%s _gather_203[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_204")); } _res = NULL; done: @@ -36371,9 +37626,9 @@ _gather_198_rule(Parser *p) return _res; } -// _loop0_201: ',' (expression ['as' star_target]) +// _loop0_206: ',' (expression ['as' star_target]) static asdl_seq * -_loop0_201_rule(Parser *p) +_loop0_206_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36399,13 +37654,13 @@ _loop0_201_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_206[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_244_rule(p)) // expression ['as' star_target] + (elem = _tmp_265_rule(p)) // expression ['as' star_target] ) { _res = elem; @@ -36431,7 +37686,7 @@ _loop0_201_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_201[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_206[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36448,9 +37703,9 @@ _loop0_201_rule(Parser *p) return _seq; } -// _gather_200: (expression ['as' star_target]) _loop0_201 +// _gather_205: (expression ['as' star_target]) _loop0_206 static asdl_seq * -_gather_200_rule(Parser *p) +_gather_205_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36462,27 +37717,27 @@ _gather_200_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expression ['as' star_target]) _loop0_201 + { // (expression ['as' star_target]) _loop0_206 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_201")); + D(fprintf(stderr, "%*c> _gather_205[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_244_rule(p)) // expression ['as' star_target] + (elem = _tmp_265_rule(p)) // expression ['as' star_target] && - (seq = _loop0_201_rule(p)) // _loop0_201 + (seq = _loop0_206_rule(p)) // _loop0_206 ) { - D(fprintf(stderr, "%*c+ _gather_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_201")); + D(fprintf(stderr, "%*c+ _gather_205[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_200[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_201")); + D(fprintf(stderr, "%*c%s _gather_205[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); } _res = NULL; done: @@ -36490,9 +37745,9 @@ _gather_200_rule(Parser *p) return _res; } -// _loop0_203: ',' (expressions ['as' star_target]) +// _loop0_208: ',' (expressions ['as' star_target]) static asdl_seq * -_loop0_203_rule(Parser *p) +_loop0_208_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36518,13 +37773,13 @@ _loop0_203_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_203[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_208[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_245_rule(p)) // expressions ['as' star_target] + (elem = _tmp_266_rule(p)) // expressions ['as' star_target] ) { _res = elem; @@ -36550,7 +37805,7 @@ _loop0_203_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_203[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_208[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36567,9 +37822,9 @@ _loop0_203_rule(Parser *p) return _seq; } -// _gather_202: (expressions ['as' star_target]) _loop0_203 +// _gather_207: (expressions ['as' star_target]) _loop0_208 static asdl_seq * -_gather_202_rule(Parser *p) +_gather_207_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36581,27 +37836,27 @@ _gather_202_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expressions ['as' star_target]) _loop0_203 + { // (expressions ['as' star_target]) _loop0_208 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_203")); + D(fprintf(stderr, "%*c> _gather_207[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_245_rule(p)) // expressions ['as' star_target] + (elem = _tmp_266_rule(p)) // expressions ['as' star_target] && - (seq = _loop0_203_rule(p)) // _loop0_203 + (seq = _loop0_208_rule(p)) // _loop0_208 ) { - D(fprintf(stderr, "%*c+ _gather_202[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_203")); + D(fprintf(stderr, "%*c+ _gather_207[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_202[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_203")); + D(fprintf(stderr, "%*c%s _gather_207[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); } _res = NULL; done: @@ -36609,9 +37864,9 @@ _gather_202_rule(Parser *p) return _res; } -// _tmp_204: 'except' | 'finally' +// _tmp_209: 'except' | 'finally' static void * -_tmp_204_rule(Parser *p) +_tmp_209_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36628,18 +37883,18 @@ _tmp_204_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_204[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); + D(fprintf(stderr, "%*c> _tmp_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 636)) // token='except' + (_keyword = _PyPegen_expect_token(p, 637)) // token='except' ) { - D(fprintf(stderr, "%*c+ _tmp_204[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); + D(fprintf(stderr, "%*c+ _tmp_209[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_204[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_209[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'except'")); } { // 'finally' @@ -36647,18 +37902,18 @@ _tmp_204_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_204[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); + D(fprintf(stderr, "%*c> _tmp_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 632)) // token='finally' + (_keyword = _PyPegen_expect_token(p, 633)) // token='finally' ) { - D(fprintf(stderr, "%*c+ _tmp_204[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); + D(fprintf(stderr, "%*c+ _tmp_209[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_204[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_209[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'finally'")); } _res = NULL; @@ -36667,9 +37922,9 @@ _tmp_204_rule(Parser *p) return _res; } -// _loop0_205: block +// _loop0_210: block static asdl_seq * -_loop0_205_rule(Parser *p) +_loop0_210_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36695,7 +37950,7 @@ _loop0_205_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_205[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); + D(fprintf(stderr, "%*c> _loop0_210[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); asdl_stmt_seq* block_var; while ( (block_var = block_rule(p)) // block @@ -36718,7 +37973,7 @@ _loop0_205_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_205[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_210[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "block")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36735,9 +37990,9 @@ _loop0_205_rule(Parser *p) return _seq; } -// _loop1_206: except_block +// _loop1_211: except_block static asdl_seq * -_loop1_206_rule(Parser *p) +_loop1_211_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36763,7 +38018,7 @@ _loop1_206_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_206[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); + D(fprintf(stderr, "%*c> _loop1_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); excepthandler_ty except_block_var; while ( (except_block_var = except_block_rule(p)) // except_block @@ -36786,7 +38041,7 @@ _loop1_206_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_206[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_211[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_block")); } if (_n == 0 || p->error_indicator) { @@ -36808,9 +38063,9 @@ _loop1_206_rule(Parser *p) return _seq; } -// _tmp_207: 'as' NAME +// _tmp_212: 'as' NAME static void * -_tmp_207_rule(Parser *p) +_tmp_212_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36827,21 +38082,21 @@ _tmp_207_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_207[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_212[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_207[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_212[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_207[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_212[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -36850,9 +38105,9 @@ _tmp_207_rule(Parser *p) return _res; } -// _loop0_208: block +// _loop0_213: block static asdl_seq * -_loop0_208_rule(Parser *p) +_loop0_213_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36878,7 +38133,7 @@ _loop0_208_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_208[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); + D(fprintf(stderr, "%*c> _loop0_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); asdl_stmt_seq* block_var; while ( (block_var = block_rule(p)) // block @@ -36901,7 +38156,7 @@ _loop0_208_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_208[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_213[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "block")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36918,9 +38173,9 @@ _loop0_208_rule(Parser *p) return _seq; } -// _loop1_209: except_star_block +// _loop1_214: except_star_block static asdl_seq * -_loop1_209_rule(Parser *p) +_loop1_214_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36946,7 +38201,7 @@ _loop1_209_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); + D(fprintf(stderr, "%*c> _loop1_214[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); excepthandler_ty except_star_block_var; while ( (except_star_block_var = except_star_block_rule(p)) // except_star_block @@ -36969,7 +38224,7 @@ _loop1_209_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_209[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_214[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_star_block")); } if (_n == 0 || p->error_indicator) { @@ -36991,9 +38246,9 @@ _loop1_209_rule(Parser *p) return _seq; } -// _tmp_210: expression ['as' NAME] +// _tmp_215: expression ['as' NAME] static void * -_tmp_210_rule(Parser *p) +_tmp_215_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37010,22 +38265,22 @@ _tmp_210_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_210[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); + D(fprintf(stderr, "%*c> _tmp_215[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_246_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_267_rule(p), !p->error_indicator) // ['as' NAME] ) { - D(fprintf(stderr, "%*c+ _tmp_210[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); + D(fprintf(stderr, "%*c+ _tmp_215[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_210[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_215[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' NAME]")); } _res = NULL; @@ -37034,9 +38289,9 @@ _tmp_210_rule(Parser *p) return _res; } -// _tmp_211: 'as' NAME +// _tmp_216: 'as' NAME static void * -_tmp_211_rule(Parser *p) +_tmp_216_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37053,21 +38308,21 @@ _tmp_211_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_216[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_211[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_216[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_211[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_216[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -37076,9 +38331,9 @@ _tmp_211_rule(Parser *p) return _res; } -// _tmp_212: 'as' NAME +// _tmp_217: 'as' NAME static void * -_tmp_212_rule(Parser *p) +_tmp_217_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37095,21 +38350,21 @@ _tmp_212_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_212[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_217[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_212[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_217[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_212[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_217[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -37118,9 +38373,9 @@ _tmp_212_rule(Parser *p) return _res; } -// _tmp_213: NEWLINE | ':' +// _tmp_218: NEWLINE | ':' static void * -_tmp_213_rule(Parser *p) +_tmp_218_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37137,18 +38392,18 @@ _tmp_213_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); Token * newline_var; if ( (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_213[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_218[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); _res = newline_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_213[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_218[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE")); } { // ':' @@ -37156,18 +38411,18 @@ _tmp_213_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_213[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_218[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_213[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_218[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -37176,9 +38431,9 @@ _tmp_213_rule(Parser *p) return _res; } -// _tmp_214: 'as' NAME +// _tmp_219: 'as' NAME static void * -_tmp_214_rule(Parser *p) +_tmp_219_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37195,21 +38450,21 @@ _tmp_214_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_214[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_219[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_214[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_219[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_214[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_219[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -37218,9 +38473,9 @@ _tmp_214_rule(Parser *p) return _res; } -// _tmp_215: 'as' NAME +// _tmp_220: 'as' NAME static void * -_tmp_215_rule(Parser *p) +_tmp_220_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37237,21 +38492,21 @@ _tmp_215_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_215[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_215[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_215[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_220[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -37260,9 +38515,9 @@ _tmp_215_rule(Parser *p) return _res; } -// _tmp_216: positional_patterns ',' +// _tmp_221: positional_patterns ',' static void * -_tmp_216_rule(Parser *p) +_tmp_221_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37279,7 +38534,7 @@ _tmp_216_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_216[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c> _tmp_221[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); Token * _literal; asdl_pattern_seq* positional_patterns_var; if ( @@ -37288,12 +38543,12 @@ _tmp_216_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_216[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c+ _tmp_221[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); _res = _PyPegen_dummy_name(p, positional_patterns_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_216[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_221[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "positional_patterns ','")); } _res = NULL; @@ -37302,9 +38557,9 @@ _tmp_216_rule(Parser *p) return _res; } -// _tmp_217: '->' expression +// _tmp_222: '->' expression static void * -_tmp_217_rule(Parser *p) +_tmp_222_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37321,7 +38576,7 @@ _tmp_217_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_217[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); Token * _literal; expr_ty expression_var; if ( @@ -37330,12 +38585,12 @@ _tmp_217_rule(Parser *p) (expression_var = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_217[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); _res = _PyPegen_dummy_name(p, _literal, expression_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_217[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_222[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'->' expression")); } _res = NULL; @@ -37344,9 +38599,9 @@ _tmp_217_rule(Parser *p) return _res; } -// _tmp_218: '(' arguments? ')' +// _tmp_223: '(' arguments? ')' static void * -_tmp_218_rule(Parser *p) +_tmp_223_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37363,7 +38618,7 @@ _tmp_218_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c> _tmp_223[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); Token * _literal; Token * _literal_1; void *_opt_var; @@ -37376,12 +38631,12 @@ _tmp_218_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_218[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c+ _tmp_223[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); _res = _PyPegen_dummy_name(p, _literal, _opt_var, _literal_1); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_218[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_223[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'")); } _res = NULL; @@ -37390,9 +38645,9 @@ _tmp_218_rule(Parser *p) return _res; } -// _tmp_219: '(' arguments? ')' +// _tmp_224: '(' arguments? ')' static void * -_tmp_219_rule(Parser *p) +_tmp_224_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37409,7 +38664,7 @@ _tmp_219_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_219[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c> _tmp_224[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); Token * _literal; Token * _literal_1; void *_opt_var; @@ -37422,12 +38677,12 @@ _tmp_219_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_219[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c+ _tmp_224[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); _res = _PyPegen_dummy_name(p, _literal, _opt_var, _literal_1); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_219[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_224[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'")); } _res = NULL; @@ -37436,9 +38691,9 @@ _tmp_219_rule(Parser *p) return _res; } -// _loop0_221: ',' double_starred_kvpair +// _loop0_226: ',' double_starred_kvpair static asdl_seq * -_loop0_221_rule(Parser *p) +_loop0_226_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37464,7 +38719,7 @@ _loop0_221_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_221[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); + D(fprintf(stderr, "%*c> _loop0_226[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); Token * _literal; KeyValuePair* elem; while ( @@ -37496,7 +38751,7 @@ _loop0_221_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_221[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_226[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' double_starred_kvpair")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37513,9 +38768,9 @@ _loop0_221_rule(Parser *p) return _seq; } -// _gather_220: double_starred_kvpair _loop0_221 +// _gather_225: double_starred_kvpair _loop0_226 static asdl_seq * -_gather_220_rule(Parser *p) +_gather_225_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37527,27 +38782,27 @@ _gather_220_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // double_starred_kvpair _loop0_221 + { // double_starred_kvpair _loop0_226 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_221")); + D(fprintf(stderr, "%*c> _gather_225[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_226")); KeyValuePair* elem; asdl_seq * seq; if ( (elem = double_starred_kvpair_rule(p)) // double_starred_kvpair && - (seq = _loop0_221_rule(p)) // _loop0_221 + (seq = _loop0_226_rule(p)) // _loop0_226 ) { - D(fprintf(stderr, "%*c+ _gather_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_221")); + D(fprintf(stderr, "%*c+ _gather_225[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_226")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_220[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_221")); + D(fprintf(stderr, "%*c%s _gather_225[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_226")); } _res = NULL; done: @@ -37555,9 +38810,9 @@ _gather_220_rule(Parser *p) return _res; } -// _tmp_222: '}' | ',' +// _tmp_227: '}' | ',' static void * -_tmp_222_rule(Parser *p) +_tmp_227_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37574,18 +38829,18 @@ _tmp_222_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_222[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_227[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } { // ',' @@ -37593,18 +38848,18 @@ _tmp_222_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_222[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_227[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -37613,9 +38868,9 @@ _tmp_222_rule(Parser *p) return _res; } -// _tmp_223: '}' | ',' +// _tmp_228: '}' | ',' static void * -_tmp_223_rule(Parser *p) +_tmp_228_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37632,18 +38887,18 @@ _tmp_223_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_223[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_223[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_228[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_223[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_228[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } { // ',' @@ -37651,18 +38906,18 @@ _tmp_223_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_223[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_223[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_228[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_223[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_228[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -37671,9 +38926,898 @@ _tmp_223_rule(Parser *p) return _res; } -// _tmp_224: star_targets '=' +// _tmp_229: yield_expr | star_expressions static void * -_tmp_224_rule(Parser *p) +_tmp_229_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // yield_expr + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + expr_ty yield_expr_var; + if ( + (yield_expr_var = yield_expr_rule(p)) // yield_expr + ) + { + D(fprintf(stderr, "%*c+ _tmp_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + _res = yield_expr_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_229[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); + } + { // star_expressions + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + expr_ty star_expressions_var; + if ( + (star_expressions_var = star_expressions_rule(p)) // star_expressions + ) + { + D(fprintf(stderr, "%*c+ _tmp_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + _res = star_expressions_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_229[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_230: yield_expr | star_expressions +static void * +_tmp_230_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // yield_expr + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + expr_ty yield_expr_var; + if ( + (yield_expr_var = yield_expr_rule(p)) // yield_expr + ) + { + D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + _res = yield_expr_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_230[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); + } + { // star_expressions + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + expr_ty star_expressions_var; + if ( + (star_expressions_var = star_expressions_rule(p)) // star_expressions + ) + { + D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + _res = star_expressions_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_230[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_231: '=' | '!' | ':' | '}' +static void * +_tmp_231_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // '=' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 22)) // token='=' + ) + { + D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); + } + { // '!' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 54)) // token='!' + ) + { + D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); + } + { // ':' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 11)) // token=':' + ) + { + D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); + } + { // '}' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 26)) // token='}' + ) + { + D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_232: yield_expr | star_expressions +static void * +_tmp_232_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // yield_expr + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + expr_ty yield_expr_var; + if ( + (yield_expr_var = yield_expr_rule(p)) // yield_expr + ) + { + D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + _res = yield_expr_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); + } + { // star_expressions + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + expr_ty star_expressions_var; + if ( + (star_expressions_var = star_expressions_rule(p)) // star_expressions + ) + { + D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + _res = star_expressions_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_233: '!' | ':' | '}' +static void * +_tmp_233_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // '!' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 54)) // token='!' + ) + { + D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); + } + { // ':' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 11)) // token=':' + ) + { + D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); + } + { // '}' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 26)) // token='}' + ) + { + D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_234: yield_expr | star_expressions +static void * +_tmp_234_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // yield_expr + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + expr_ty yield_expr_var; + if ( + (yield_expr_var = yield_expr_rule(p)) // yield_expr + ) + { + D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + _res = yield_expr_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); + } + { // star_expressions + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + expr_ty star_expressions_var; + if ( + (star_expressions_var = star_expressions_rule(p)) // star_expressions + ) + { + D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + _res = star_expressions_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_235: yield_expr | star_expressions +static void * +_tmp_235_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // yield_expr + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + expr_ty yield_expr_var; + if ( + (yield_expr_var = yield_expr_rule(p)) // yield_expr + ) + { + D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + _res = yield_expr_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); + } + { // star_expressions + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + expr_ty star_expressions_var; + if ( + (star_expressions_var = star_expressions_rule(p)) // star_expressions + ) + { + D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + _res = star_expressions_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_236: '!' NAME +static void * +_tmp_236_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // '!' NAME + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + Token * _literal; + expr_ty name_var; + if ( + (_literal = _PyPegen_expect_token(p, 54)) // token='!' + && + (name_var = _PyPegen_name_token(p)) // NAME + ) + { + D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + _res = _PyPegen_dummy_name(p, _literal, name_var); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_237: ':' | '}' +static void * +_tmp_237_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // ':' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 11)) // token=':' + ) + { + D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); + } + { // '}' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 26)) // token='}' + ) + { + D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_238: yield_expr | star_expressions +static void * +_tmp_238_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // yield_expr + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + expr_ty yield_expr_var; + if ( + (yield_expr_var = yield_expr_rule(p)) // yield_expr + ) + { + D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + _res = yield_expr_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); + } + { // star_expressions + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + expr_ty star_expressions_var; + if ( + (star_expressions_var = star_expressions_rule(p)) // star_expressions + ) + { + D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + _res = star_expressions_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_239: '!' NAME +static void * +_tmp_239_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // '!' NAME + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + Token * _literal; + expr_ty name_var; + if ( + (_literal = _PyPegen_expect_token(p, 54)) // token='!' + && + (name_var = _PyPegen_name_token(p)) // NAME + ) + { + D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + _res = _PyPegen_dummy_name(p, _literal, name_var); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _loop0_240: fstring_format_spec +static asdl_seq * +_loop0_240_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // fstring_format_spec + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop0_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); + expr_ty fstring_format_spec_var; + while ( + (fstring_format_spec_var = fstring_format_spec_rule(p)) // fstring_format_spec + ) + { + _res = fstring_format_spec_var; + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop0_240[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_format_spec")); + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _tmp_241: yield_expr | star_expressions +static void * +_tmp_241_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // yield_expr + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + expr_ty yield_expr_var; + if ( + (yield_expr_var = yield_expr_rule(p)) // yield_expr + ) + { + D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + _res = yield_expr_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); + } + { // star_expressions + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + expr_ty star_expressions_var; + if ( + (star_expressions_var = star_expressions_rule(p)) // star_expressions + ) + { + D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + _res = star_expressions_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_242: '!' NAME +static void * +_tmp_242_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // '!' NAME + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + Token * _literal; + expr_ty name_var; + if ( + (_literal = _PyPegen_expect_token(p, 54)) // token='!' + && + (name_var = _PyPegen_name_token(p)) // NAME + ) + { + D(fprintf(stderr, "%*c+ _tmp_242[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + _res = _PyPegen_dummy_name(p, _literal, name_var); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_242[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_243: ':' | '}' +static void * +_tmp_243_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // ':' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 11)) // token=':' + ) + { + D(fprintf(stderr, "%*c+ _tmp_243[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); + } + { // '}' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 26)) // token='}' + ) + { + D(fprintf(stderr, "%*c+ _tmp_243[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_244: star_targets '=' +static void * +_tmp_244_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37690,7 +39834,7 @@ _tmp_224_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_224[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty z; if ( @@ -37699,7 +39843,7 @@ _tmp_224_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_224[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_244[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -37709,7 +39853,7 @@ _tmp_224_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_224[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_244[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -37718,9 +39862,9 @@ _tmp_224_rule(Parser *p) return _res; } -// _tmp_225: '.' | '...' +// _tmp_245: '.' | '...' static void * -_tmp_225_rule(Parser *p) +_tmp_245_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37737,18 +39881,18 @@ _tmp_225_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_225[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_225[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_225[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -37756,18 +39900,18 @@ _tmp_225_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_225[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_225[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_225[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -37776,9 +39920,9 @@ _tmp_225_rule(Parser *p) return _res; } -// _tmp_226: '.' | '...' +// _tmp_246: '.' | '...' static void * -_tmp_226_rule(Parser *p) +_tmp_246_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37795,18 +39939,18 @@ _tmp_226_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_226[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_226[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_226[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -37814,18 +39958,18 @@ _tmp_226_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_226[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_226[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_226[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -37834,9 +39978,9 @@ _tmp_226_rule(Parser *p) return _res; } -// _tmp_227: '@' named_expression NEWLINE +// _tmp_247: '@' named_expression NEWLINE static void * -_tmp_227_rule(Parser *p) +_tmp_247_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37853,7 +39997,7 @@ _tmp_227_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); Token * _literal; expr_ty f; Token * newline_var; @@ -37865,7 +40009,7 @@ _tmp_227_rule(Parser *p) (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); _res = f; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -37875,7 +40019,7 @@ _tmp_227_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_227[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@' named_expression NEWLINE")); } _res = NULL; @@ -37884,9 +40028,9 @@ _tmp_227_rule(Parser *p) return _res; } -// _tmp_228: ',' expression +// _tmp_248: ',' expression static void * -_tmp_228_rule(Parser *p) +_tmp_248_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37903,7 +40047,7 @@ _tmp_228_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty c; if ( @@ -37912,7 +40056,7 @@ _tmp_228_rule(Parser *p) (c = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_228[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -37922,7 +40066,7 @@ _tmp_228_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_228[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } _res = NULL; @@ -37931,9 +40075,9 @@ _tmp_228_rule(Parser *p) return _res; } -// _tmp_229: ',' star_expression +// _tmp_249: ',' star_expression static void * -_tmp_229_rule(Parser *p) +_tmp_249_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37950,7 +40094,7 @@ _tmp_229_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); Token * _literal; expr_ty c; if ( @@ -37959,7 +40103,7 @@ _tmp_229_rule(Parser *p) (c = star_expression_rule(p)) // star_expression ) { - D(fprintf(stderr, "%*c+ _tmp_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -37969,7 +40113,7 @@ _tmp_229_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_229[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_expression")); } _res = NULL; @@ -37978,9 +40122,9 @@ _tmp_229_rule(Parser *p) return _res; } -// _tmp_230: 'or' conjunction +// _tmp_250: 'or' conjunction static void * -_tmp_230_rule(Parser *p) +_tmp_250_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37997,7 +40141,7 @@ _tmp_230_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); Token * _keyword; expr_ty c; if ( @@ -38006,7 +40150,7 @@ _tmp_230_rule(Parser *p) (c = conjunction_rule(p)) // conjunction ) { - D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -38016,7 +40160,7 @@ _tmp_230_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_230[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_250[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'or' conjunction")); } _res = NULL; @@ -38025,9 +40169,9 @@ _tmp_230_rule(Parser *p) return _res; } -// _tmp_231: 'and' inversion +// _tmp_251: 'and' inversion static void * -_tmp_231_rule(Parser *p) +_tmp_251_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38044,7 +40188,7 @@ _tmp_231_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c> _tmp_251[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); Token * _keyword; expr_ty c; if ( @@ -38053,7 +40197,7 @@ _tmp_231_rule(Parser *p) (c = inversion_rule(p)) // inversion ) { - D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c+ _tmp_251[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -38063,7 +40207,7 @@ _tmp_231_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_251[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'and' inversion")); } _res = NULL; @@ -38072,9 +40216,9 @@ _tmp_231_rule(Parser *p) return _res; } -// _tmp_232: slice | starred_expression +// _tmp_252: slice | starred_expression static void * -_tmp_232_rule(Parser *p) +_tmp_252_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38091,18 +40235,18 @@ _tmp_232_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c> _tmp_252[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); expr_ty slice_var; if ( (slice_var = slice_rule(p)) // slice ) { - D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c+ _tmp_252[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); _res = slice_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_252[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slice")); } { // starred_expression @@ -38110,18 +40254,18 @@ _tmp_232_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_252[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression ) { - D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_252[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_252[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } _res = NULL; @@ -38130,9 +40274,67 @@ _tmp_232_rule(Parser *p) return _res; } -// _tmp_233: 'if' disjunction +// _tmp_253: fstring | string static void * -_tmp_233_rule(Parser *p) +_tmp_253_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // fstring + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring")); + expr_ty fstring_var; + if ( + (fstring_var = fstring_rule(p)) // fstring + ) + { + D(fprintf(stderr, "%*c+ _tmp_253[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring")); + _res = fstring_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_253[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring")); + } + { // string + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string")); + expr_ty string_var; + if ( + (string_var = string_rule(p)) // string + ) + { + D(fprintf(stderr, "%*c+ _tmp_253[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "string")); + _res = string_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_253[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "string")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_254: 'if' disjunction +static void * +_tmp_254_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38149,16 +40351,16 @@ _tmp_233_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( - (_keyword = _PyPegen_expect_token(p, 641)) // token='if' + (_keyword = _PyPegen_expect_token(p, 642)) // token='if' && (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -38168,7 +40370,7 @@ _tmp_233_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); } _res = NULL; @@ -38177,9 +40379,9 @@ _tmp_233_rule(Parser *p) return _res; } -// _tmp_234: 'if' disjunction +// _tmp_255: 'if' disjunction static void * -_tmp_234_rule(Parser *p) +_tmp_255_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38196,16 +40398,16 @@ _tmp_234_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_255[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( - (_keyword = _PyPegen_expect_token(p, 641)) // token='if' + (_keyword = _PyPegen_expect_token(p, 642)) // token='if' && (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_255[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -38215,7 +40417,7 @@ _tmp_234_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); } _res = NULL; @@ -38224,9 +40426,9 @@ _tmp_234_rule(Parser *p) return _res; } -// _tmp_235: starred_expression | (assignment_expression | expression !':=') !'=' +// _tmp_256: starred_expression | (assignment_expression | expression !':=') !'=' static void * -_tmp_235_rule(Parser *p) +_tmp_256_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38243,18 +40445,18 @@ _tmp_235_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression ) { - D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } { // (assignment_expression | expression !':=') !'=' @@ -38262,20 +40464,20 @@ _tmp_235_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); - void *_tmp_247_var; + D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + void *_tmp_268_var; if ( - (_tmp_247_var = _tmp_247_rule(p)) // assignment_expression | expression !':=' + (_tmp_268_var = _tmp_268_rule(p)) // assignment_expression | expression !':=' && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); - _res = _tmp_247_var; + D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + _res = _tmp_268_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(assignment_expression | expression !':=') !'='")); } _res = NULL; @@ -38284,9 +40486,9 @@ _tmp_235_rule(Parser *p) return _res; } -// _tmp_236: ',' star_target +// _tmp_257: ',' star_target static void * -_tmp_236_rule(Parser *p) +_tmp_257_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38303,7 +40505,7 @@ _tmp_236_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -38312,7 +40514,7 @@ _tmp_236_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -38322,7 +40524,7 @@ _tmp_236_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_257[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } _res = NULL; @@ -38331,9 +40533,9 @@ _tmp_236_rule(Parser *p) return _res; } -// _tmp_237: ',' star_target +// _tmp_258: ',' star_target static void * -_tmp_237_rule(Parser *p) +_tmp_258_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38350,7 +40552,7 @@ _tmp_237_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_258[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -38359,7 +40561,7 @@ _tmp_237_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_258[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -38369,7 +40571,7 @@ _tmp_237_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_258[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } _res = NULL; @@ -38378,9 +40580,9 @@ _tmp_237_rule(Parser *p) return _res; } -// _tmp_238: star_targets '=' +// _tmp_259: star_targets '=' static void * -_tmp_238_rule(Parser *p) +_tmp_259_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38397,7 +40599,7 @@ _tmp_238_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_259[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty star_targets_var; if ( @@ -38406,12 +40608,12 @@ _tmp_238_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_259[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = _PyPegen_dummy_name(p, star_targets_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_259[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -38420,9 +40622,9 @@ _tmp_238_rule(Parser *p) return _res; } -// _tmp_239: star_targets '=' +// _tmp_260: star_targets '=' static void * -_tmp_239_rule(Parser *p) +_tmp_260_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38439,7 +40641,7 @@ _tmp_239_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_260[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty star_targets_var; if ( @@ -38448,12 +40650,12 @@ _tmp_239_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_260[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = _PyPegen_dummy_name(p, star_targets_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_260[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -38462,9 +40664,9 @@ _tmp_239_rule(Parser *p) return _res; } -// _tmp_240: ')' | '**' +// _tmp_261: ')' | '**' static void * -_tmp_240_rule(Parser *p) +_tmp_261_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38481,18 +40683,18 @@ _tmp_240_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_261[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_240[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_261[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_261[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // '**' @@ -38500,18 +40702,18 @@ _tmp_240_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_261[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_240[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_261[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_261[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; @@ -38520,9 +40722,9 @@ _tmp_240_rule(Parser *p) return _res; } -// _tmp_241: ':' | '**' +// _tmp_262: ':' | '**' static void * -_tmp_241_rule(Parser *p) +_tmp_262_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38539,18 +40741,18 @@ _tmp_241_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_262[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_262[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_262[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '**' @@ -38558,18 +40760,18 @@ _tmp_241_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_262[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_262[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_262[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; @@ -38578,9 +40780,9 @@ _tmp_241_rule(Parser *p) return _res; } -// _tmp_242: expression ['as' star_target] +// _tmp_263: expression ['as' star_target] static void * -_tmp_242_rule(Parser *p) +_tmp_263_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38597,22 +40799,22 @@ _tmp_242_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_263[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_248_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_269_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_242[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_263[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_242[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_263[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' star_target]")); } _res = NULL; @@ -38621,9 +40823,9 @@ _tmp_242_rule(Parser *p) return _res; } -// _tmp_243: expressions ['as' star_target] +// _tmp_264: expressions ['as' star_target] static void * -_tmp_243_rule(Parser *p) +_tmp_264_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38640,22 +40842,22 @@ _tmp_243_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expressions_var; if ( (expressions_var = expressions_rule(p)) // expressions && - (_opt_var = _tmp_249_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_270_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_243[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); _res = _PyPegen_dummy_name(p, expressions_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_264[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expressions ['as' star_target]")); } _res = NULL; @@ -38664,9 +40866,9 @@ _tmp_243_rule(Parser *p) return _res; } -// _tmp_244: expression ['as' star_target] +// _tmp_265: expression ['as' star_target] static void * -_tmp_244_rule(Parser *p) +_tmp_265_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38683,22 +40885,22 @@ _tmp_244_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_265[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_250_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_271_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_244[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_265[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_244[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_265[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' star_target]")); } _res = NULL; @@ -38707,9 +40909,9 @@ _tmp_244_rule(Parser *p) return _res; } -// _tmp_245: expressions ['as' star_target] +// _tmp_266: expressions ['as' star_target] static void * -_tmp_245_rule(Parser *p) +_tmp_266_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38726,22 +40928,22 @@ _tmp_245_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_266[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expressions_var; if ( (expressions_var = expressions_rule(p)) // expressions && - (_opt_var = _tmp_251_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_272_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_266[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); _res = _PyPegen_dummy_name(p, expressions_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_266[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expressions ['as' star_target]")); } _res = NULL; @@ -38750,9 +40952,9 @@ _tmp_245_rule(Parser *p) return _res; } -// _tmp_246: 'as' NAME +// _tmp_267: 'as' NAME static void * -_tmp_246_rule(Parser *p) +_tmp_267_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38769,21 +40971,21 @@ _tmp_246_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_267[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_267[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_267[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38792,9 +40994,9 @@ _tmp_246_rule(Parser *p) return _res; } -// _tmp_247: assignment_expression | expression !':=' +// _tmp_268: assignment_expression | expression !':=' static void * -_tmp_247_rule(Parser *p) +_tmp_268_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38811,18 +41013,18 @@ _tmp_247_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c> _tmp_268[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); expr_ty assignment_expression_var; if ( (assignment_expression_var = assignment_expression_rule(p)) // assignment_expression ) { - D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c+ _tmp_268[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); _res = assignment_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_268[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "assignment_expression")); } { // expression !':=' @@ -38830,7 +41032,7 @@ _tmp_247_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c> _tmp_268[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression @@ -38838,12 +41040,12 @@ _tmp_247_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 53) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c+ _tmp_268[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); _res = expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_268[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression !':='")); } _res = NULL; @@ -38852,9 +41054,9 @@ _tmp_247_rule(Parser *p) return _res; } -// _tmp_248: 'as' star_target +// _tmp_269: 'as' star_target static void * -_tmp_248_rule(Parser *p) +_tmp_269_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38871,21 +41073,21 @@ _tmp_248_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_269[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_269[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_269[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -38894,9 +41096,9 @@ _tmp_248_rule(Parser *p) return _res; } -// _tmp_249: 'as' star_target +// _tmp_270: 'as' star_target static void * -_tmp_249_rule(Parser *p) +_tmp_270_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38913,21 +41115,21 @@ _tmp_249_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_270[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_270[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_270[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -38936,9 +41138,9 @@ _tmp_249_rule(Parser *p) return _res; } -// _tmp_250: 'as' star_target +// _tmp_271: 'as' star_target static void * -_tmp_250_rule(Parser *p) +_tmp_271_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38955,21 +41157,21 @@ _tmp_250_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_271[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_271[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_250[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_271[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -38978,9 +41180,9 @@ _tmp_250_rule(Parser *p) return _res; } -// _tmp_251: 'as' star_target +// _tmp_272: 'as' star_target static void * -_tmp_251_rule(Parser *p) +_tmp_272_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38997,21 +41199,21 @@ _tmp_251_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_251[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_272[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( - (_keyword = _PyPegen_expect_token(p, 639)) // token='as' + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' && (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_251[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_272[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_251[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_272[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; diff --git a/Parser/pegen.c b/Parser/pegen.c index b79ae4cb1fb3..262bfabfba7a 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -359,7 +359,7 @@ _PyPegen_expect_token(Parser *p, int type) } Token *t = p->tokens[p->mark]; if (t->type != type) { - return NULL; + return NULL; } p->mark += 1; return t; diff --git a/Parser/pegen.h b/Parser/pegen.h index ad5c97f5f7e5..6962013c2d18 100644 --- a/Parser/pegen.h +++ b/Parser/pegen.h @@ -138,6 +138,7 @@ void* _PyPegen_expect_forced_result(Parser *p, void* result, const char* expecte Token *_PyPegen_expect_forced_token(Parser *p, int type, const char* expected); expr_ty _PyPegen_expect_soft_keyword(Parser *p, const char *keyword); expr_ty _PyPegen_soft_keyword_token(Parser *p); +expr_ty _PyPegen_fstring_middle_token(Parser* p); Token *_PyPegen_get_last_nonnwhitespace_token(Parser *); int _PyPegen_fill_token(Parser *p); expr_ty _PyPegen_name_token(Parser *p); @@ -155,7 +156,7 @@ typedef enum { int _Pypegen_raise_decode_error(Parser *p); void _PyPegen_raise_tokenizer_init_error(PyObject *filename); int _Pypegen_tokenizer_error(Parser *p); -void *_PyPegen_raise_error(Parser *p, PyObject *errtype, const char *errmsg, ...); +void *_PyPegen_raise_error(Parser *p, PyObject *errtype, int use_mark, const char *errmsg, ...); void *_PyPegen_raise_error_known_location(Parser *p, PyObject *errtype, Py_ssize_t lineno, Py_ssize_t col_offset, Py_ssize_t end_lineno, Py_ssize_t end_col_offset, @@ -175,8 +176,9 @@ RAISE_ERROR_KNOWN_LOCATION(Parser *p, PyObject *errtype, va_end(va); return NULL; } -#define RAISE_SYNTAX_ERROR(msg, ...) _PyPegen_raise_error(p, PyExc_SyntaxError, msg, ##__VA_ARGS__) -#define RAISE_INDENTATION_ERROR(msg, ...) _PyPegen_raise_error(p, PyExc_IndentationError, msg, ##__VA_ARGS__) +#define RAISE_SYNTAX_ERROR(msg, ...) _PyPegen_raise_error(p, PyExc_SyntaxError, 0, msg, ##__VA_ARGS__) +#define RAISE_INDENTATION_ERROR(msg, ...) _PyPegen_raise_error(p, PyExc_IndentationError, 0, msg, ##__VA_ARGS__) +#define RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN(msg, ...) _PyPegen_raise_error(p, PyExc_SyntaxError, 1, msg, ##__VA_ARGS__) #define RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, msg, ...) \ RAISE_ERROR_KNOWN_LOCATION(p, PyExc_SyntaxError, (a)->lineno, (a)->col_offset, (b)->end_lineno, (b)->end_col_offset, msg, ##__VA_ARGS__) #define RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, msg, ...) \ @@ -308,6 +310,7 @@ StarEtc *_PyPegen_star_etc(Parser *, arg_ty, asdl_seq *, arg_ty); arguments_ty _PyPegen_make_arguments(Parser *, asdl_arg_seq *, SlashWithDefault *, asdl_arg_seq *, asdl_seq *, StarEtc *); arguments_ty _PyPegen_empty_arguments(Parser *); +expr_ty _PyPegen_formatted_value(Parser *, expr_ty, Token *, expr_ty, expr_ty, int, int, int, int, PyArena *); AugOperator *_PyPegen_augoperator(Parser*, operator_ty type); stmt_ty _PyPegen_function_def_decorators(Parser *, asdl_expr_seq *, stmt_ty); stmt_ty _PyPegen_class_def_decorators(Parser *, asdl_expr_seq *, stmt_ty); @@ -317,12 +320,16 @@ asdl_keyword_seq *_PyPegen_seq_delete_starred_exprs(Parser *, asdl_seq *); expr_ty _PyPegen_collect_call_seqs(Parser *, asdl_expr_seq *, asdl_seq *, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena); -expr_ty _PyPegen_concatenate_strings(Parser *p, asdl_seq *); +expr_ty _PyPegen_constant_from_token(Parser* p, Token* tok); +expr_ty _PyPegen_constant_from_string(Parser* p, Token* tok); +expr_ty _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *, int, int, int, int, PyArena *); +expr_ty _PyPegen_FetchRawForm(Parser *p, int, int, int, int); expr_ty _PyPegen_ensure_imaginary(Parser *p, expr_ty); expr_ty _PyPegen_ensure_real(Parser *p, expr_ty); asdl_seq *_PyPegen_join_sequences(Parser *, asdl_seq *, asdl_seq *); int _PyPegen_check_barry_as_flufl(Parser *, Token *); int _PyPegen_check_legacy_stmt(Parser *p, expr_ty t); +expr_ty _PyPegen_check_fstring_conversion(Parser *p, Token *, expr_ty t); mod_ty _PyPegen_make_module(Parser *, asdl_stmt_seq *); void *_PyPegen_arguments_parsing_error(Parser *, expr_ty); expr_ty _PyPegen_get_last_comprehension_item(comprehension_ty comprehension); @@ -338,6 +345,9 @@ void *_PyPegen_run_parser(Parser *); mod_ty _PyPegen_run_parser_from_string(const char *, int, PyObject *, PyCompilerFlags *, PyArena *); asdl_stmt_seq *_PyPegen_interactive_exit(Parser *); +// TODO: move to the correct place in this file +expr_ty _PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* expr, Token*b); + // Generated function in parse.c - function definition in python.gram void *_PyPegen_parse(Parser *); diff --git a/Parser/pegen_errors.c b/Parser/pegen_errors.c index 6ea7600119b6..e26bad20a275 100644 --- a/Parser/pegen_errors.c +++ b/Parser/pegen_errors.c @@ -192,7 +192,10 @@ _PyPegen_tokenize_full_source_to_check_for_errors(Parser *p) { exit: - if (PyErr_Occurred()) { + // If we're in an f-string, we want the syntax error in the expression part + // to propagate, so that tokenizer errors (like expecting '}') that happen afterwards + // do not swallow it. + if (PyErr_Occurred() && p->tok->tok_mode_stack_index <= 0) { Py_XDECREF(value); Py_XDECREF(type); Py_XDECREF(traceback); @@ -205,7 +208,7 @@ _PyPegen_tokenize_full_source_to_check_for_errors(Parser *p) { // PARSER ERRORS void * -_PyPegen_raise_error(Parser *p, PyObject *errtype, const char *errmsg, ...) +_PyPegen_raise_error(Parser *p, PyObject *errtype, int use_mark, const char *errmsg, ...) { if (p->fill == 0) { va_list va; @@ -214,8 +217,13 @@ _PyPegen_raise_error(Parser *p, PyObject *errtype, const char *errmsg, ...) va_end(va); return NULL; } - - Token *t = p->known_err_token != NULL ? p->known_err_token : p->tokens[p->fill - 1]; + if (use_mark && p->mark == p->fill && _PyPegen_fill_token(p) < 0) { + p->error_indicator = 1; + return NULL; + } + Token *t = p->known_err_token != NULL + ? p->known_err_token + : p->tokens[use_mark ? p->mark : p->fill - 1]; Py_ssize_t col_offset; Py_ssize_t end_col_offset = -1; if (t->col_offset == -1) { diff --git a/Parser/string_parser.c b/Parser/string_parser.c index c096bea7426e..be5f0c4a60a6 100644 --- a/Parser/string_parser.c +++ b/Parser/string_parser.c @@ -135,7 +135,9 @@ decode_unicode_with_escapes(Parser *parser, const char *s, size_t len, Token *t) const char *first_invalid_escape; v = _PyUnicode_DecodeUnicodeEscapeInternal(s, len, NULL, NULL, &first_invalid_escape); - if (v != NULL && first_invalid_escape != NULL) { + // HACK: later we can simply pass the line no, since we don't preserve the tokens + // when we are decoding the string but we preserve the line numbers. + if (v != NULL && first_invalid_escape != NULL && t != NULL) { if (warn_invalid_escape_sequence(parser, first_invalid_escape, t) < 0) { /* We have not decref u before because first_invalid_escape points inside u. */ @@ -166,43 +168,43 @@ decode_bytes_with_escapes(Parser *p, const char *s, Py_ssize_t len, Token *t) return result; } -/* s must include the bracketing quote characters, and r, b, u, - &/or f prefixes (if any), and embedded escape sequences (if any). - _PyPegen_parsestr parses it, and sets *result to decoded Python string object. - If the string is an f-string, set *fstr and *fstrlen to the unparsed - string object. Return 0 if no errors occurred. */ -int -_PyPegen_parsestr(Parser *p, int *bytesmode, int *rawmode, PyObject **result, - const char **fstr, Py_ssize_t *fstrlen, Token *t) +PyObject * +_PyPegen_decode_string(Parser *p, int raw, const char *s, size_t len, Token *t) +{ + if (raw) { + return PyUnicode_DecodeUTF8Stateful(s, len, NULL, NULL); + } + return decode_unicode_with_escapes(p, s, len, t); +} + +/* s must include the bracketing quote characters, and r, b &/or f prefixes + (if any), and embedded escape sequences (if any). (f-strings are handled by the parser) + _PyPegen_parse_string parses it, and returns the decoded Python string object. */ +PyObject * +_PyPegen_parse_string(Parser *p, Token *t) { const char *s = PyBytes_AsString(t->bytes); if (s == NULL) { - return -1; + return NULL; } size_t len; int quote = Py_CHARMASK(*s); - int fmode = 0; - *bytesmode = 0; - *rawmode = 0; - *result = NULL; - *fstr = NULL; + int bytesmode = 0; + int rawmode = 0; + if (Py_ISALPHA(quote)) { - while (!*bytesmode || !*rawmode) { + while (!bytesmode || !rawmode) { if (quote == 'b' || quote == 'B') { quote =(unsigned char)*++s; - *bytesmode = 1; + bytesmode = 1; } else if (quote == 'u' || quote == 'U') { quote = (unsigned char)*++s; } else if (quote == 'r' || quote == 'R') { quote = (unsigned char)*++s; - *rawmode = 1; - } - else if (quote == 'f' || quote == 'F') { - quote = (unsigned char)*++s; - fmode = 1; + rawmode = 1; } else { break; @@ -210,32 +212,21 @@ _PyPegen_parsestr(Parser *p, int *bytesmode, int *rawmode, PyObject **result, } } - /* fstrings are only allowed in Python 3.6 and greater */ - if (fmode && p->feature_version < 6) { - p->error_indicator = 1; - RAISE_SYNTAX_ERROR("Format strings are only supported in Python 3.6 and greater"); - return -1; - } - - if (fmode && *bytesmode) { - PyErr_BadInternalCall(); - return -1; - } if (quote != '\'' && quote != '\"') { PyErr_BadInternalCall(); - return -1; + return NULL; } /* Skip the leading quote char. */ s++; len = strlen(s); if (len > INT_MAX) { PyErr_SetString(PyExc_OverflowError, "string to parse is too long"); - return -1; + return NULL; } if (s[--len] != quote) { /* Last quote char must match the first. */ PyErr_BadInternalCall(); - return -1; + return NULL; } if (len >= 4 && s[0] == quote && s[1] == quote) { /* A triple quoted string. We've already skipped one quote at @@ -246,22 +237,13 @@ _PyPegen_parsestr(Parser *p, int *bytesmode, int *rawmode, PyObject **result, /* And check that the last two match. */ if (s[--len] != quote || s[--len] != quote) { PyErr_BadInternalCall(); - return -1; + return NULL; } } - if (fmode) { - /* Just return the bytes. The caller will parse the resulting - string. */ - *fstr = s; - *fstrlen = len; - return 0; - } - - /* Not an f-string. */ /* Avoid invoking escape decoding routines if possible. */ - *rawmode = *rawmode || strchr(s, '\\') == NULL; - if (*bytesmode) { + rawmode = rawmode || strchr(s, '\\') == NULL; + if (bytesmode) { /* Disallow non-ASCII characters. */ const char *ch; for (ch = s; *ch; ch++) { @@ -269,1014 +251,13 @@ _PyPegen_parsestr(Parser *p, int *bytesmode, int *rawmode, PyObject **result, RAISE_SYNTAX_ERROR( "bytes can only contain ASCII " "literal characters"); - return -1; - } - } - if (*rawmode) { - *result = PyBytes_FromStringAndSize(s, len); - } - else { - *result = decode_bytes_with_escapes(p, s, len, t); - } - } - else { - if (*rawmode) { - *result = PyUnicode_DecodeUTF8Stateful(s, len, NULL, NULL); - } - else { - *result = decode_unicode_with_escapes(p, s, len, t); - } - } - return *result == NULL ? -1 : 0; -} - - - -// FSTRING STUFF - -/* Fix locations for the given node and its children. - - `parent` is the enclosing node. - `expr_start` is the starting position of the expression (pointing to the open brace). - `n` is the node which locations are going to be fixed relative to parent. - `expr_str` is the child node's string representation, including braces. -*/ -static bool -fstring_find_expr_location(Token *parent, const char* expr_start, char *expr_str, int *p_lines, int *p_cols) -{ - *p_lines = 0; - *p_cols = 0; - assert(expr_start != NULL && *expr_start == '{'); - if (parent && parent->bytes) { - const char *parent_str = PyBytes_AsString(parent->bytes); - if (!parent_str) { - return false; - } - // The following is needed, in order to correctly shift the column - // offset, in the case that (disregarding any whitespace) a newline - // immediately follows the opening curly brace of the fstring expression. - bool newline_after_brace = 1; - const char *start = expr_start + 1; - while (start && *start != '}' && *start != '\n') { - if (*start != ' ' && *start != '\t' && *start != '\f') { - newline_after_brace = 0; - break; - } - start++; - } - - // Account for the characters from the last newline character to our - // left until the beginning of expr_start. - if (!newline_after_brace) { - start = expr_start; - while (start > parent_str && *start != '\n') { - start--; - } - *p_cols += (int)(expr_start - start); - if (*start == '\n') { - *p_cols -= 1; - } - } - /* adjust the start based on the number of newlines encountered - before the f-string expression */ - for (const char *p = parent_str; p < expr_start; p++) { - if (*p == '\n') { - (*p_lines)++; - } - } - } - return true; -} - - -/* Compile this expression in to an expr_ty. Add parens around the - expression, in order to allow leading spaces in the expression. */ -static expr_ty -fstring_compile_expr(Parser *p, const char *expr_start, const char *expr_end, - Token *t) -{ - expr_ty expr = NULL; - char *str; - Py_ssize_t len; - const char *s; - expr_ty result = NULL; - - assert(expr_end >= expr_start); - assert(*(expr_start-1) == '{'); - assert(*expr_end == '}' || *expr_end == '!' || *expr_end == ':' || - *expr_end == '='); - - /* If the substring is all whitespace, it's an error. We need to catch this - here, and not when we call PyParser_SimpleParseStringFlagsFilename, - because turning the expression '' in to '()' would go from being invalid - to valid. */ - for (s = expr_start; s != expr_end; s++) { - char c = *s; - /* The Python parser ignores only the following whitespace - characters (\r already is converted to \n). */ - if (!(c == ' ' || c == '\t' || c == '\n' || c == '\f')) { - break; - } - } - - if (s == expr_end) { - if (*expr_end == '!' || *expr_end == ':' || *expr_end == '=') { - RAISE_SYNTAX_ERROR("f-string: expression required before '%c'", *expr_end); - return NULL; - } - RAISE_SYNTAX_ERROR("f-string: empty expression not allowed"); - return NULL; - } - - len = expr_end - expr_start; - /* Allocate 3 extra bytes: open paren, close paren, null byte. */ - str = PyMem_Calloc(len + 3, sizeof(char)); - if (str == NULL) { - PyErr_NoMemory(); - return NULL; - } - - // The call to fstring_find_expr_location is responsible for finding the column offset - // the generated AST nodes need to be shifted to the right, which is equal to the number - // of the f-string characters before the expression starts. - memcpy(str+1, expr_start, len); - int lines, cols; - if (!fstring_find_expr_location(t, expr_start-1, str+1, &lines, &cols)) { - PyMem_Free(str); - return NULL; - } - - // The parentheses are needed in order to allow for leading whitespace within - // the f-string expression. This consequently gets parsed as a group (see the - // group rule in python.gram). - str[0] = '('; - str[len+1] = ')'; - - struct tok_state* tok = _PyTokenizer_FromString(str, 1); - if (tok == NULL) { - PyMem_Free(str); - return NULL; - } - tok->filename = Py_NewRef(p->tok->filename); - tok->lineno = t->lineno + lines - 1; - - Parser *p2 = _PyPegen_Parser_New(tok, Py_fstring_input, p->flags, p->feature_version, - NULL, p->arena); - - p2->starting_lineno = t->lineno + lines; - p2->starting_col_offset = lines != 0 ? cols : t->col_offset + cols; - - expr = _PyPegen_run_parser(p2); - - if (expr == NULL) { - goto exit; - } - result = expr; - -exit: - PyMem_Free(str); - _PyPegen_Parser_Free(p2); - _PyTokenizer_Free(tok); - return result; -} - -/* Return -1 on error. - - Return 0 if we reached the end of the literal. - - Return 1 if we haven't reached the end of the literal, but we want - the caller to process the literal up to this point. Used for - doubled braces. -*/ -static int -fstring_find_literal(Parser *p, const char **str, const char *end, int raw, - PyObject **literal, int recurse_lvl, Token *t) -{ - /* Get any literal string. It ends when we hit an un-doubled left - brace (which isn't part of a unicode name escape such as - "\N{EULER CONSTANT}"), or the end of the string. */ - - const char *s = *str; - const char *literal_start = s; - int result = 0; - - assert(*literal == NULL); - while (s < end) { - char ch = *s++; - if (!raw && ch == '\\' && s < end) { - ch = *s++; - if (ch == 'N') { - /* We need to look at and skip matching braces for "\N{name}" - sequences because otherwise we'll think the opening '{' - starts an expression, which is not the case with "\N". - Keep looking for either a matched '{' '}' pair, or the end - of the string. */ - - if (s < end && *s++ == '{') { - while (s < end && *s++ != '}') { - } - continue; - } - - /* This is an invalid "\N" sequence, since it's a "\N" not - followed by a "{". Just keep parsing this literal. This - error will be caught later by - decode_unicode_with_escapes(). */ - continue; - } - if (ch == '{' && warn_invalid_escape_sequence(p, s-1, t) < 0) { - return -1; - } - } - if (ch == '{' || ch == '}') { - /* Check for doubled braces, but only at the top level. If - we checked at every level, then f'{0:{3}}' would fail - with the two closing braces. */ - if (recurse_lvl == 0) { - if (s < end && *s == ch) { - /* We're going to tell the caller that the literal ends - here, but that they should continue scanning. But also - skip over the second brace when we resume scanning. */ - *str = s + 1; - result = 1; - goto done; - } - - /* Where a single '{' is the start of a new expression, a - single '}' is not allowed. */ - if (ch == '}') { - *str = s - 1; - RAISE_SYNTAX_ERROR("f-string: single '}' is not allowed"); - return -1; - } - } - /* We're either at a '{', which means we're starting another - expression; or a '}', which means we're at the end of this - f-string (for a nested format_spec). */ - s--; - break; - } - } - *str = s; - assert(s <= end); - assert(s == end || *s == '{' || *s == '}'); -done: - if (literal_start != s) { - if (raw) { - *literal = PyUnicode_DecodeUTF8Stateful(literal_start, - s - literal_start, - NULL, NULL); - } - else { - *literal = decode_unicode_with_escapes(p, literal_start, - s - literal_start, t); - } - if (!*literal) { - return -1; - } - } - return result; -} - -/* Forward declaration because parsing is recursive. */ -static expr_ty -fstring_parse(Parser *p, const char **str, const char *end, int raw, int recurse_lvl, - Token *first_token, Token* t, Token *last_token); - -/* Parse the f-string at *str, ending at end. We know *str starts an - expression (so it must be a '{'). Returns the FormattedValue node, which - includes the expression, conversion character, format_spec expression, and - optionally the text of the expression (if = is used). - - Note that I don't do a perfect job here: I don't make sure that a - closing brace doesn't match an opening paren, for example. It - doesn't need to error on all invalid expressions, just correctly - find the end of all valid ones. Any errors inside the expression - will be caught when we parse it later. - - *expression is set to the expression. For an '=' "debug" expression, - *expr_text is set to the debug text (the original text of the expression, - including the '=' and any whitespace around it, as a string object). If - not a debug expression, *expr_text set to NULL. */ -static int -fstring_find_expr(Parser *p, const char **str, const char *end, int raw, int recurse_lvl, - PyObject **expr_text, expr_ty *expression, Token *first_token, - Token *t, Token *last_token) -{ - /* Return -1 on error, else 0. */ - - const char *expr_start; - const char *expr_end; - expr_ty simple_expression; - expr_ty format_spec = NULL; /* Optional format specifier. */ - int conversion = -1; /* The conversion char. Use default if not - specified, or !r if using = and no format - spec. */ - - /* 0 if we're not in a string, else the quote char we're trying to - match (single or double quote). */ - char quote_char = 0; - - /* If we're inside a string, 1=normal, 3=triple-quoted. */ - int string_type = 0; - - /* Keep track of nesting level for braces/parens/brackets in - expressions. */ - Py_ssize_t nested_depth = 0; - char parenstack[MAXLEVEL]; - - *expr_text = NULL; - - /* Can only nest one level deep. */ - if (recurse_lvl >= 2) { - RAISE_SYNTAX_ERROR("f-string: expressions nested too deeply"); - goto error; - } - - /* The first char must be a left brace, or we wouldn't have gotten - here. Skip over it. */ - assert(**str == '{'); - *str += 1; - - expr_start = *str; - for (; *str < end; (*str)++) { - char ch; - - /* Loop invariants. */ - assert(nested_depth >= 0); - assert(*str >= expr_start && *str < end); - if (quote_char) { - assert(string_type == 1 || string_type == 3); - } else { - assert(string_type == 0); - } - - ch = **str; - /* Nowhere inside an expression is a backslash allowed. */ - if (ch == '\\') { - /* Error: can't include a backslash character, inside - parens or strings or not. */ - RAISE_SYNTAX_ERROR( - "f-string expression part " - "cannot include a backslash"); - goto error; - } - if (quote_char) { - /* We're inside a string. See if we're at the end. */ - /* This code needs to implement the same non-error logic - as tok_get from tokenizer.c, at the letter_quote - label. To actually share that code would be a - nightmare. But, it's unlikely to change and is small, - so duplicate it here. Note we don't need to catch all - of the errors, since they'll be caught when parsing the - expression. We just need to match the non-error - cases. Thus we can ignore \n in single-quoted strings, - for example. Or non-terminated strings. */ - if (ch == quote_char) { - /* Does this match the string_type (single or triple - quoted)? */ - if (string_type == 3) { - if (*str+2 < end && *(*str+1) == ch && *(*str+2) == ch) { - /* We're at the end of a triple quoted string. */ - *str += 2; - string_type = 0; - quote_char = 0; - continue; - } - } else { - /* We're at the end of a normal string. */ - quote_char = 0; - string_type = 0; - continue; - } - } - } else if (ch == '\'' || ch == '"') { - /* Is this a triple quoted string? */ - if (*str+2 < end && *(*str+1) == ch && *(*str+2) == ch) { - string_type = 3; - *str += 2; - } else { - /* Start of a normal string. */ - string_type = 1; - } - /* Start looking for the end of the string. */ - quote_char = ch; - } else if (ch == '[' || ch == '{' || ch == '(') { - if (nested_depth >= MAXLEVEL) { - RAISE_SYNTAX_ERROR("f-string: too many nested parenthesis"); - goto error; - } - parenstack[nested_depth] = ch; - nested_depth++; - } else if (ch == '#') { - /* Error: can't include a comment character, inside parens - or not. */ - RAISE_SYNTAX_ERROR("f-string expression part cannot include '#'"); - goto error; - } else if (nested_depth == 0 && - (ch == '!' || ch == ':' || ch == '}' || - ch == '=' || ch == '>' || ch == '<')) { - /* See if there's a next character. */ - if (*str+1 < end) { - char next = *(*str+1); - - /* For "!=". since '=' is not an allowed conversion character, - nothing is lost in this test. */ - if ((ch == '!' && next == '=') || /* != */ - (ch == '=' && next == '=') || /* == */ - (ch == '<' && next == '=') || /* <= */ - (ch == '>' && next == '=') /* >= */ - ) { - *str += 1; - continue; - } - } - /* Don't get out of the loop for these, if they're single - chars (not part of 2-char tokens). If by themselves, they - don't end an expression (unlike say '!'). */ - if (ch == '>' || ch == '<') { - continue; - } - - /* Normal way out of this loop. */ - break; - } else if (ch == ']' || ch == '}' || ch == ')') { - if (!nested_depth) { - RAISE_SYNTAX_ERROR("f-string: unmatched '%c'", ch); - goto error; - } - nested_depth--; - int opening = (unsigned char)parenstack[nested_depth]; - if (!((opening == '(' && ch == ')') || - (opening == '[' && ch == ']') || - (opening == '{' && ch == '}'))) - { - RAISE_SYNTAX_ERROR( - "f-string: closing parenthesis '%c' " - "does not match opening parenthesis '%c'", - ch, opening); - goto error; - } - } else { - /* Just consume this char and loop around. */ - } - } - expr_end = *str; - /* If we leave the above loop in a string or with mismatched parens, we - don't really care. We'll get a syntax error when compiling the - expression. But, we can produce a better error message, so let's just - do that.*/ - if (quote_char) { - RAISE_SYNTAX_ERROR("f-string: unterminated string"); - goto error; - } - if (nested_depth) { - int opening = (unsigned char)parenstack[nested_depth - 1]; - RAISE_SYNTAX_ERROR("f-string: unmatched '%c'", opening); - goto error; - } - - if (*str >= end) { - goto unexpected_end_of_string; - } - - /* Compile the expression as soon as possible, so we show errors - related to the expression before errors related to the - conversion or format_spec. */ - simple_expression = fstring_compile_expr(p, expr_start, expr_end, t); - if (!simple_expression) { - goto error; - } - - /* Check for =, which puts the text value of the expression in - expr_text. */ - if (**str == '=') { - if (p->feature_version < 8) { - RAISE_SYNTAX_ERROR("f-string: self documenting expressions are " - "only supported in Python 3.8 and greater"); - goto error; - } - *str += 1; - - /* Skip over ASCII whitespace. No need to test for end of string - here, since we know there's at least a trailing quote somewhere - ahead. */ - while (Py_ISSPACE(**str)) { - *str += 1; - } - if (*str >= end) { - goto unexpected_end_of_string; - } - /* Set *expr_text to the text of the expression. */ - *expr_text = PyUnicode_FromStringAndSize(expr_start, *str-expr_start); - if (!*expr_text) { - goto error; - } - } - - /* Check for a conversion char, if present. */ - if (**str == '!') { - *str += 1; - const char *conv_start = *str; - while (1) { - if (*str >= end) { - goto unexpected_end_of_string; - } - if (**str == '}' || **str == ':') { - break; - } - *str += 1; - } - if (*str == conv_start) { - RAISE_SYNTAX_ERROR( - "f-string: missed conversion character"); - goto error; - } - - conversion = (unsigned char)*conv_start; - /* Validate the conversion. */ - if ((*str != conv_start + 1) || - !(conversion == 's' || conversion == 'r' || conversion == 'a')) - { - PyObject *conv_obj = PyUnicode_FromStringAndSize(conv_start, - *str-conv_start); - if (conv_obj) { - RAISE_SYNTAX_ERROR( - "f-string: invalid conversion character %R: " - "expected 's', 'r', or 'a'", - conv_obj); - Py_DECREF(conv_obj); - } - goto error; - } - - } - - /* Check for the format spec, if present. */ - assert(*str < end); - if (**str == ':') { - *str += 1; - if (*str >= end) { - goto unexpected_end_of_string; - } - - /* Parse the format spec. */ - format_spec = fstring_parse(p, str, end, raw, recurse_lvl+1, - first_token, t, last_token); - if (!format_spec) { - goto error; - } - } - - if (*str >= end || **str != '}') { - goto unexpected_end_of_string; - } - - /* We're at a right brace. Consume it. */ - assert(*str < end); - assert(**str == '}'); - *str += 1; - - /* If we're in = mode (detected by non-NULL expr_text), and have no format - spec and no explicit conversion, set the conversion to 'r'. */ - if (*expr_text && format_spec == NULL && conversion == -1) { - conversion = 'r'; - } - - /* And now create the FormattedValue node that represents this - entire expression with the conversion and format spec. */ - //TODO: Fix this - *expression = _PyAST_FormattedValue(simple_expression, conversion, - format_spec, first_token->lineno, - first_token->col_offset, - last_token->end_lineno, - last_token->end_col_offset, p->arena); - if (!*expression) { - goto error; - } - - return 0; - -unexpected_end_of_string: - RAISE_SYNTAX_ERROR("f-string: expecting '}'"); - /* Falls through to error. */ - -error: - Py_XDECREF(*expr_text); - return -1; - -} - -/* Return -1 on error. - - Return 0 if we have a literal (possible zero length) and an - expression (zero length if at the end of the string. - - Return 1 if we have a literal, but no expression, and we want the - caller to call us again. This is used to deal with doubled - braces. - - When called multiple times on the string 'a{{b{0}c', this function - will return: - - 1. the literal 'a{' with no expression, and a return value - of 1. Despite the fact that there's no expression, the return - value of 1 means we're not finished yet. - - 2. the literal 'b' and the expression '0', with a return value of - 0. The fact that there's an expression means we're not finished. - - 3. literal 'c' with no expression and a return value of 0. The - combination of the return value of 0 with no expression means - we're finished. -*/ -static int -fstring_find_literal_and_expr(Parser *p, const char **str, const char *end, int raw, - int recurse_lvl, PyObject **literal, - PyObject **expr_text, expr_ty *expression, - Token *first_token, Token *t, Token *last_token) -{ - int result; - - assert(*literal == NULL && *expression == NULL); - - /* Get any literal string. */ - result = fstring_find_literal(p, str, end, raw, literal, recurse_lvl, t); - if (result < 0) { - goto error; - } - - assert(result == 0 || result == 1); - - if (result == 1) { - /* We have a literal, but don't look at the expression. */ - return 1; - } - - if (*str >= end || **str == '}') { - /* We're at the end of the string or the end of a nested - f-string: no expression. The top-level error case where we - expect to be at the end of the string but we're at a '}' is - handled later. */ - return 0; - } - - /* We must now be the start of an expression, on a '{'. */ - assert(**str == '{'); - - if (fstring_find_expr(p, str, end, raw, recurse_lvl, expr_text, - expression, first_token, t, last_token) < 0) { - goto error; - } - - return 0; - -error: - Py_CLEAR(*literal); - return -1; -} - -#ifdef NDEBUG -#define ExprList_check_invariants(l) -#else -static void -ExprList_check_invariants(ExprList *l) -{ - /* Check our invariants. Make sure this object is "live", and - hasn't been deallocated. */ - assert(l->size >= 0); - assert(l->p != NULL); - if (l->size <= EXPRLIST_N_CACHED) { - assert(l->data == l->p); - } -} -#endif - -static void -ExprList_Init(ExprList *l) -{ - l->allocated = EXPRLIST_N_CACHED; - l->size = 0; - - /* Until we start allocating dynamically, p points to data. */ - l->p = l->data; - - ExprList_check_invariants(l); -} - -static int -ExprList_Append(ExprList *l, expr_ty exp) -{ - ExprList_check_invariants(l); - if (l->size >= l->allocated) { - /* We need to alloc (or realloc) the memory. */ - Py_ssize_t new_size = l->allocated * 2; - - /* See if we've ever allocated anything dynamically. */ - if (l->p == l->data) { - Py_ssize_t i; - /* We're still using the cached data. Switch to - alloc-ing. */ - l->p = PyMem_Malloc(sizeof(expr_ty) * new_size); - if (!l->p) { - return -1; - } - /* Copy the cached data into the new buffer. */ - for (i = 0; i < l->size; i++) { - l->p[i] = l->data[i]; - } - } else { - /* Just realloc. */ - expr_ty *tmp = PyMem_Realloc(l->p, sizeof(expr_ty) * new_size); - if (!tmp) { - PyMem_Free(l->p); - l->p = NULL; - return -1; - } - l->p = tmp; - } - - l->allocated = new_size; - assert(l->allocated == 2 * l->size); - } - - l->p[l->size++] = exp; - - ExprList_check_invariants(l); - return 0; -} - -static void -ExprList_Dealloc(ExprList *l) -{ - ExprList_check_invariants(l); - - /* If there's been an error, or we've never dynamically allocated, - do nothing. */ - if (!l->p || l->p == l->data) { - /* Do nothing. */ - } else { - /* We have dynamically allocated. Free the memory. */ - PyMem_Free(l->p); - } - l->p = NULL; - l->size = -1; -} - -static asdl_expr_seq * -ExprList_Finish(ExprList *l, PyArena *arena) -{ - asdl_expr_seq *seq; - - ExprList_check_invariants(l); - - /* Allocate the asdl_seq and copy the expressions in to it. */ - seq = _Py_asdl_expr_seq_new(l->size, arena); - if (seq) { - Py_ssize_t i; - for (i = 0; i < l->size; i++) { - asdl_seq_SET(seq, i, l->p[i]); - } - } - ExprList_Dealloc(l); - return seq; -} - -#ifdef NDEBUG -#define FstringParser_check_invariants(state) -#else -static void -FstringParser_check_invariants(FstringParser *state) -{ - if (state->last_str) { - assert(PyUnicode_CheckExact(state->last_str)); - } - ExprList_check_invariants(&state->expr_list); -} -#endif - -void -_PyPegen_FstringParser_Init(FstringParser *state) -{ - state->last_str = NULL; - state->fmode = 0; - ExprList_Init(&state->expr_list); - FstringParser_check_invariants(state); -} - -void -_PyPegen_FstringParser_Dealloc(FstringParser *state) -{ - FstringParser_check_invariants(state); - - Py_XDECREF(state->last_str); - ExprList_Dealloc(&state->expr_list); -} - -/* Make a Constant node, but decref the PyUnicode object being added. */ -static expr_ty -make_str_node_and_del(Parser *p, PyObject **str, Token* first_token, Token *last_token) -{ - PyObject *s = *str; - PyObject *kind = NULL; - *str = NULL; - assert(PyUnicode_CheckExact(s)); - if (_PyArena_AddPyObject(p->arena, s) < 0) { - Py_DECREF(s); - return NULL; - } - const char* the_str = PyBytes_AsString(first_token->bytes); - if (the_str && the_str[0] == 'u') { - kind = _PyPegen_new_identifier(p, "u"); - } - - if (kind == NULL && PyErr_Occurred()) { - return NULL; - } - - return _PyAST_Constant(s, kind, first_token->lineno, first_token->col_offset, - last_token->end_lineno, last_token->end_col_offset, - p->arena); - -} - - -/* Add a non-f-string (that is, a regular literal string). str is - decref'd. */ -int -_PyPegen_FstringParser_ConcatAndDel(FstringParser *state, PyObject *str) -{ - FstringParser_check_invariants(state); - - assert(PyUnicode_CheckExact(str)); - - if (PyUnicode_GET_LENGTH(str) == 0) { - Py_DECREF(str); - return 0; - } - - if (!state->last_str) { - /* We didn't have a string before, so just remember this one. */ - state->last_str = str; - } else { - /* Concatenate this with the previous string. */ - PyUnicode_AppendAndDel(&state->last_str, str); - if (!state->last_str) { - return -1; - } - } - FstringParser_check_invariants(state); - return 0; -} - -/* Parse an f-string. The f-string is in *str to end, with no - 'f' or quotes. */ -int -_PyPegen_FstringParser_ConcatFstring(Parser *p, FstringParser *state, const char **str, - const char *end, int raw, int recurse_lvl, - Token *first_token, Token* t, Token *last_token) -{ - FstringParser_check_invariants(state); - state->fmode = 1; - - /* Parse the f-string. */ - while (1) { - PyObject *literal = NULL; - PyObject *expr_text = NULL; - expr_ty expression = NULL; - - /* If there's a zero length literal in front of the - expression, literal will be NULL. If we're at the end of - the f-string, expression will be NULL (unless result == 1, - see below). */ - int result = fstring_find_literal_and_expr(p, str, end, raw, recurse_lvl, - &literal, &expr_text, - &expression, first_token, t, last_token); - if (result < 0) { - return -1; - } - - /* Add the literal, if any. */ - if (literal && _PyPegen_FstringParser_ConcatAndDel(state, literal) < 0) { - Py_XDECREF(expr_text); - return -1; - } - /* Add the expr_text, if any. */ - if (expr_text && _PyPegen_FstringParser_ConcatAndDel(state, expr_text) < 0) { - return -1; - } - - /* We've dealt with the literal and expr_text, their ownership has - been transferred to the state object. Don't look at them again. */ - - /* See if we should just loop around to get the next literal - and expression, while ignoring the expression this - time. This is used for un-doubling braces, as an - optimization. */ - if (result == 1) { - continue; - } - - if (!expression) { - /* We're done with this f-string. */ - break; - } - - /* We know we have an expression. Convert any existing string - to a Constant node. */ - if (state->last_str) { - /* Convert the existing last_str literal to a Constant node. */ - expr_ty last_str = make_str_node_and_del(p, &state->last_str, first_token, last_token); - if (!last_str || ExprList_Append(&state->expr_list, last_str) < 0) { - return -1; - } - } - - if (ExprList_Append(&state->expr_list, expression) < 0) { - return -1; - } - } - - /* If recurse_lvl is zero, then we must be at the end of the - string. Otherwise, we must be at a right brace. */ - - if (recurse_lvl == 0 && *str < end-1) { - RAISE_SYNTAX_ERROR("f-string: unexpected end of string"); - return -1; - } - if (recurse_lvl != 0 && **str != '}') { - RAISE_SYNTAX_ERROR("f-string: expecting '}'"); - return -1; - } - - FstringParser_check_invariants(state); - return 0; -} - -/* Convert the partial state reflected in last_str and expr_list to an - expr_ty. The expr_ty can be a Constant, or a JoinedStr. */ -expr_ty -_PyPegen_FstringParser_Finish(Parser *p, FstringParser *state, Token* first_token, - Token *last_token) -{ - asdl_expr_seq *seq; - - FstringParser_check_invariants(state); - - /* If we're just a constant string with no expressions, return - that. */ - if (!state->fmode) { - assert(!state->expr_list.size); - if (!state->last_str) { - /* Create a zero length string. */ - state->last_str = PyUnicode_FromStringAndSize(NULL, 0); - if (!state->last_str) { - goto error; + return NULL; } } - return make_str_node_and_del(p, &state->last_str, first_token, last_token); - } - - /* Create a Constant node out of last_str, if needed. It will be the - last node in our expression list. */ - if (state->last_str) { - expr_ty str = make_str_node_and_del(p, &state->last_str, first_token, last_token); - if (!str || ExprList_Append(&state->expr_list, str) < 0) { - goto error; + if (rawmode) { + return PyBytes_FromStringAndSize(s, len); } + return decode_bytes_with_escapes(p, s, len, t); } - /* This has already been freed. */ - assert(state->last_str == NULL); - - seq = ExprList_Finish(&state->expr_list, p->arena); - if (!seq) { - goto error; - } - - return _PyAST_JoinedStr(seq, first_token->lineno, first_token->col_offset, - last_token->end_lineno, last_token->end_col_offset, - p->arena); - -error: - _PyPegen_FstringParser_Dealloc(state); - return NULL; -} - -/* Given an f-string (with no 'f' or quotes) that's in *str and ends - at end, parse it into an expr_ty. Return NULL on error. Adjust - str to point past the parsed portion. */ -static expr_ty -fstring_parse(Parser *p, const char **str, const char *end, int raw, - int recurse_lvl, Token *first_token, Token* t, Token *last_token) -{ - FstringParser state; - - _PyPegen_FstringParser_Init(&state); - if (_PyPegen_FstringParser_ConcatFstring(p, &state, str, end, raw, recurse_lvl, - first_token, t, last_token) < 0) { - _PyPegen_FstringParser_Dealloc(&state); - return NULL; - } - - return _PyPegen_FstringParser_Finish(p, &state, t, t); + return _PyPegen_decode_string(p, rawmode, s, len, t); } diff --git a/Parser/string_parser.h b/Parser/string_parser.h index 4a22f3d3086f..0b34de1b4e41 100644 --- a/Parser/string_parser.h +++ b/Parser/string_parser.h @@ -5,42 +5,7 @@ #include #include "pegen.h" -#define EXPRLIST_N_CACHED 64 - -typedef struct { - /* Incrementally build an array of expr_ty, so be used in an - asdl_seq. Cache some small but reasonably sized number of - expr_ty's, and then after that start dynamically allocating, - doubling the number allocated each time. Note that the f-string - f'{0}a{1}' contains 3 expr_ty's: 2 FormattedValue's, and one - Constant for the literal 'a'. So you add expr_ty's about twice as - fast as you add expressions in an f-string. */ - - Py_ssize_t allocated; /* Number we've allocated. */ - Py_ssize_t size; /* Number we've used. */ - expr_ty *p; /* Pointer to the memory we're actually - using. Will point to 'data' until we - start dynamically allocating. */ - expr_ty data[EXPRLIST_N_CACHED]; -} ExprList; - -/* The FstringParser is designed to add a mix of strings and - f-strings, and concat them together as needed. Ultimately, it - generates an expr_ty. */ -typedef struct { - PyObject *last_str; - ExprList expr_list; - int fmode; -} FstringParser; - -void _PyPegen_FstringParser_Init(FstringParser *); -int _PyPegen_parsestr(Parser *, int *, int *, PyObject **, - const char **, Py_ssize_t *, Token *); -int _PyPegen_FstringParser_ConcatFstring(Parser *, FstringParser *, const char **, - const char *, int, int, Token *, Token *, - Token *); -int _PyPegen_FstringParser_ConcatAndDel(FstringParser *, PyObject *); -expr_ty _PyPegen_FstringParser_Finish(Parser *, FstringParser *, Token *, Token *); -void _PyPegen_FstringParser_Dealloc(FstringParser *); +PyObject *_PyPegen_parse_string(Parser *, Token *); +PyObject *_PyPegen_decode_string(Parser *, int, const char *, size_t, Token *); #endif diff --git a/Parser/token.c b/Parser/token.c index 6299ad2f5631..82267fbfcd0c 100644 --- a/Parser/token.c +++ b/Parser/token.c @@ -60,12 +60,16 @@ const char * const _PyParser_TokenNames[] = { "RARROW", "ELLIPSIS", "COLONEQUAL", + "EXCLAMATION", "OP", "AWAIT", "ASYNC", "TYPE_IGNORE", "TYPE_COMMENT", "SOFT_KEYWORD", + "FSTRING_START", + "FSTRING_MIDDLE", + "FSTRING_END", "", "", "", @@ -79,6 +83,7 @@ int _PyToken_OneChar(int c1) { switch (c1) { + case '!': return EXCLAMATION; case '%': return PERCENT; case '&': return AMPER; case '(': return LPAR; diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 463c0e00ca14..1dfd2d6e5e17 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -43,6 +43,28 @@ tok->lineno++; \ tok->col_offset = 0; +#ifdef Py_DEBUG +static inline tokenizer_mode* TOK_GET_MODE(struct tok_state* tok) { + assert(tok->tok_mode_stack_index >= 0); + assert(tok->tok_mode_stack_index < MAXLEVEL); + return &(tok->tok_mode_stack[tok->tok_mode_stack_index]); +} +static inline tokenizer_mode* TOK_NEXT_MODE(struct tok_state* tok) { + assert(tok->tok_mode_stack_index >= 0); + assert(tok->tok_mode_stack_index < MAXLEVEL); + return &(tok->tok_mode_stack[++tok->tok_mode_stack_index]); +} +static inline int *TOK_GET_BRACKET_MARK(tokenizer_mode* mode) { + assert(mode->bracket_mark_index >= 0); + assert(mode->bracket_mark_index < MAX_EXPR_NESTING); + return &(mode->bracket_mark[mode->bracket_mark_index]); +} +#else +#define TOK_GET_MODE(tok) (&(tok->tok_mode_stack[tok->tok_mode_stack_index])) +#define TOK_NEXT_MODE(tok) (&(tok->tok_mode_stack[++tok->tok_mode_stack_index])) +#define TOK_GET_BRACKET_MARK(mode) (&(mode->bracket_mark[mode->bracket_mark_index])) +#endif + /* Forward */ static struct tok_state *tok_new(void); static int tok_nextc(struct tok_state *tok); @@ -98,6 +120,9 @@ tok_new(void) tok->interactive_underflow = IUNDERFLOW_NORMAL; tok->str = NULL; tok->report_warnings = 1; + tok->tok_mode_stack[0] = (tokenizer_mode){.kind =TOK_REGULAR_MODE, .f_string_quote='\0', .f_string_quote_size = 0}; + tok->tok_mode_stack_index = 0; + tok->tok_report_warnings = 1; #ifdef Py_DEBUG tok->debug = _Py_GetConfig()->parser_debug; #endif @@ -346,6 +371,92 @@ tok_concatenate_interactive_new_line(struct tok_state *tok, const char *line) { } +/* Traverse and update all f-string buffers with the value */ +static void +update_fstring_buffers(struct tok_state *tok, char value, int regular, int multiline) +{ + int index; + tokenizer_mode *mode; + + for (index = tok->tok_mode_stack_index; index >= 0; --index) { + mode = &(tok->tok_mode_stack[index]); + if (regular && mode->f_string_start != NULL) { + mode->f_string_start += value; + } + if (multiline && mode->f_string_multi_line_start != NULL) { + mode->f_string_multi_line_start += value; + } + } +} + +static int +update_fstring_expr(struct tok_state *tok, char cur) +{ + assert(tok->cur != NULL); + + Py_ssize_t size = strlen(tok->cur); + tokenizer_mode *tok_mode = TOK_GET_MODE(tok); + + switch (cur) { + case '{': + if (tok_mode->last_expr_buffer != NULL) { + PyMem_Free(tok_mode->last_expr_buffer); + } + tok_mode->last_expr_buffer = PyMem_Malloc(size); + if (tok_mode->last_expr_buffer == NULL) { + tok->done = E_NOMEM; + return 0; + } + tok_mode->last_expr_size = size; + tok_mode->last_expr_end = -1; + strncpy(tok_mode->last_expr_buffer, tok->cur, size); + break; + case 0: + if (!tok_mode->last_expr_buffer || tok_mode->last_expr_end >= 0) { + return 1; + } + char *new_buffer = PyMem_Realloc( + tok_mode->last_expr_buffer, + tok_mode->last_expr_size + size + ); + if (new_buffer == NULL) { + PyMem_Free(tok_mode->last_expr_buffer); + tok->done = E_NOMEM; + return 0; + } + tok_mode->last_expr_buffer = new_buffer; + strncpy(tok_mode->last_expr_buffer + tok_mode->last_expr_size, tok->cur, size); + tok_mode->last_expr_size += size; + break; + case '}': + case '!': + case ':': + if (tok_mode->last_expr_end == -1) { + tok_mode->last_expr_end = strlen(tok->start); + } + break; + } + + return 1; +} + +static void +free_fstring_expressions(struct tok_state *tok) +{ + int index; + tokenizer_mode *mode; + + for (index = tok->tok_mode_stack_index; index >= 0; --index) { + mode = &(tok->tok_mode_stack[index]); + if (mode->last_expr_buffer != NULL) { + PyMem_Free(mode->last_expr_buffer); + mode->last_expr_buffer = NULL; + mode->last_expr_size = 0; + mode->last_expr_end = -1; + } + } +} + /* Read a line of text from TOK into S, using the stream in TOK. Return NULL on failure, else S. @@ -372,6 +483,7 @@ tok_reserve_buf(struct tok_state *tok, Py_ssize_t size) Py_ssize_t start = tok->start == NULL ? -1 : tok->start - tok->buf; Py_ssize_t line_start = tok->start == NULL ? -1 : tok->line_start - tok->buf; Py_ssize_t multi_line_start = tok->multi_line_start - tok->buf; + update_fstring_buffers(tok, -*tok->buf, /*regular=*/1, /*multiline=*/1); newbuf = (char *)PyMem_Realloc(newbuf, newsize); if (newbuf == NULL) { tok->done = E_NOMEM; @@ -384,6 +496,7 @@ tok_reserve_buf(struct tok_state *tok, Py_ssize_t size) tok->start = start < 0 ? NULL : tok->buf + start; tok->line_start = line_start < 0 ? NULL : tok->buf + line_start; tok->multi_line_start = multi_line_start < 0 ? NULL : tok->buf + multi_line_start; + update_fstring_buffers(tok, *tok->buf, /*regular=*/1, /*multiline=*/1); } return 1; } @@ -838,6 +951,7 @@ _PyTokenizer_Free(struct tok_state *tok) if (tok->interactive_src_start != NULL) { PyMem_Free(tok->interactive_src_start); } + free_fstring_expressions(tok); PyMem_Free(tok); } @@ -854,6 +968,9 @@ tok_readline_raw(struct tok_state *tok) if (line == NULL) { return 1; } + if (tok->tok_mode_stack_index && !update_fstring_expr(tok, 0)) { + return 0; + } if (tok->fp_interactive && tok_concatenate_interactive_new_line(tok, line) == -1) { return 0; @@ -941,6 +1058,7 @@ tok_underflow_interactive(struct tok_state *tok) { } else if (tok->start != NULL) { Py_ssize_t cur_multi_line_start = tok->multi_line_start - tok->buf; + update_fstring_buffers(tok, -*tok->buf, /*regular=*/0, /*multiline=*/1); size_t size = strlen(newtok); ADVANCE_LINENO(); if (!tok_reserve_buf(tok, size + 1)) { @@ -953,6 +1071,7 @@ tok_underflow_interactive(struct tok_state *tok) { PyMem_Free(newtok); tok->inp += size; tok->multi_line_start = tok->buf + cur_multi_line_start; + update_fstring_buffers(tok, *tok->buf, /*regular=*/0, /*multiline=*/1); } else { ADVANCE_LINENO(); @@ -969,6 +1088,10 @@ tok_underflow_interactive(struct tok_state *tok) { } return 0; } + + if (tok->tok_mode_stack_index && !update_fstring_expr(tok, 0)) { + return 0; + } return 1; } @@ -1073,7 +1196,7 @@ tok_nextc(struct tok_state *tok) return Py_CHARMASK(*tok->cur++); /* Fast path */ } if (tok->done != E_OK) { - return EOF; + return EOF; } if (tok->fp == NULL) { rc = tok_underflow_string(tok); @@ -1115,7 +1238,7 @@ tok_backup(struct tok_state *tok, int c) if (--tok->cur < tok->buf) { Py_FatalError("tokenizer beginning of buffer"); } - if ((int)(unsigned char)*tok->cur != c) { + if ((int)(unsigned char)*tok->cur != Py_CHARMASK(c)) { Py_FatalError("tok_backup: wrong character"); } tok->col_offset--; @@ -1172,6 +1295,7 @@ _syntaxerror_range(struct tok_state *tok, const char *format, static int syntaxerror(struct tok_state *tok, const char *format, ...) { + // This errors are cleaned on startup. Todo: Fix it. va_list vargs; va_start(vargs, format); int ret = _syntaxerror_range(tok, format, -1, -1, vargs); @@ -1234,6 +1358,41 @@ parser_warn(struct tok_state *tok, PyObject *category, const char *format, ...) return -1; } +static int +warn_invalid_escape_sequence(struct tok_state *tok, int first_invalid_escape_char) +{ + + if (!tok->tok_report_warnings) { + return 0; + } + + PyObject *msg = PyUnicode_FromFormat( + "invalid escape sequence '\\%c'", + (char) first_invalid_escape_char + ); + + if (msg == NULL) { + return -1; + } + + if (PyErr_WarnExplicitObject(PyExc_DeprecationWarning, msg, tok->filename, + tok->lineno, NULL, NULL) < 0) { + Py_DECREF(msg); + + if (PyErr_ExceptionMatches(PyExc_DeprecationWarning)) { + /* Replace the DeprecationWarning exception with a SyntaxError + to get a more accurate error report */ + PyErr_Clear(); + return syntaxerror(tok, "invalid escape sequence '\\%c'", (char) first_invalid_escape_char); + } + + return -1; + } + + Py_DECREF(msg); + return 0; +} + static int lookahead(struct tok_state *tok, const char *test) { @@ -1389,7 +1548,6 @@ tok_decimal_tail(struct tok_state *tok) return c; } -/* Get next token, after space stripping etc. */ static inline int tok_continuation_line(struct tok_state *tok) { @@ -1427,7 +1585,12 @@ token_setup(struct tok_state *tok, struct token *token, int type, const char *st { assert((start == NULL && end == NULL) || (start != NULL && end != NULL)); token->level = tok->level; - token->lineno = type == STRING ? tok->first_lineno : tok->lineno; + if (ISSTRINGLIT(type)) { + token->lineno = tok->first_lineno; + } + else { + token->lineno = tok->lineno; + } token->end_lineno = tok->lineno; token->col_offset = token->end_col_offset = -1; token->start = start; @@ -1441,7 +1604,7 @@ token_setup(struct tok_state *tok, struct token *token, int type, const char *st } static int -tok_get(struct tok_state *tok, struct token *token) +tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct token *token) { int c; int blankline, nonascii; @@ -1602,6 +1765,11 @@ tok_get(struct tok_state *tok, struct token *token) /* Skip comment, unless it's a type comment */ if (c == '#') { + + if (tok->tok_mode_stack_index > 0) { + return MAKE_TOKEN(syntaxerror(tok, "f-string expression part cannot include '#'")); + } + const char *prefix, *p, *type_start; int current_starting_col_offset; @@ -1703,6 +1871,9 @@ tok_get(struct tok_state *tok, struct token *token) } c = tok_nextc(tok); if (c == '"' || c == '\'') { + if (saw_f) { + goto f_string_quote; + } goto letter_quote; } } @@ -1748,7 +1919,9 @@ tok_get(struct tok_state *tok, struct token *token) int ahead_tok_kind; memcpy(&ahead_tok, tok, sizeof(ahead_tok)); - ahead_tok_kind = tok_get(&ahead_tok, &ahead_token); + ahead_tok_kind = tok_get_normal_mode(&ahead_tok, + current_tok, + &ahead_token); if (ahead_tok_kind == NAME && ahead_tok.cur - ahead_tok.start == 3 @@ -2003,6 +2176,67 @@ tok_get(struct tok_state *tok, struct token *token) return MAKE_TOKEN(NUMBER); } + f_string_quote: + if (((tolower(*tok->start) == 'f' || tolower(*tok->start) == 'r') && (c == '\'' || c == '"'))) { + int quote = c; + int quote_size = 1; /* 1 or 3 */ + + /* Nodes of type STRING, especially multi line strings + must be handled differently in order to get both + the starting line number and the column offset right. + (cf. issue 16806) */ + tok->first_lineno = tok->lineno; + tok->multi_line_start = tok->line_start; + + /* Find the quote size and start of string */ + int after_quote = tok_nextc(tok); + if (after_quote == quote) { + int after_after_quote = tok_nextc(tok); + if (after_after_quote == quote) { + quote_size = 3; + } + else { + // TODO: Check this + tok_backup(tok, after_after_quote); + tok_backup(tok, after_quote); + } + } + if (after_quote != quote) { + tok_backup(tok, after_quote); + } + + + p_start = tok->start; + p_end = tok->cur; + tokenizer_mode *current_tok = TOK_NEXT_MODE(tok); + current_tok->kind = TOK_FSTRING_MODE; + current_tok->f_string_quote = quote; + current_tok->f_string_quote_size = quote_size; + current_tok->f_string_start = tok->start; + current_tok->f_string_multi_line_start = tok->line_start; + current_tok->last_expr_buffer = NULL; + current_tok->last_expr_size = 0; + current_tok->last_expr_end = -1; + + switch (*tok->start) { + case 'F': + case 'f': + current_tok->f_string_raw = tolower(*(tok->start + 1)) == 'r'; + break; + case 'R': + case 'r': + current_tok->f_string_raw = 1; + break; + default: + Py_UNREACHABLE(); + } + + current_tok->bracket_stack = 0; + current_tok->bracket_mark[0] = 0; + current_tok->bracket_mark_index = -1; + return MAKE_TOKEN(FSTRING_START); + } + letter_quote: /* String */ if (c == '\'' || c == '"') { @@ -2047,6 +2281,20 @@ tok_get(struct tok_state *tok, struct token *token) tok->line_start = tok->multi_line_start; int start = tok->lineno; tok->lineno = tok->first_lineno; + + if (tok->tok_mode_stack_index > 0) { + /* When we are in an f-string, before raising the + * unterminated string literal error, check whether + * does the initial quote matches with f-strings quotes + * and if it is, then this must be a missing '}' token + * so raise the proper error */ + tokenizer_mode *current_tok = TOK_GET_MODE(tok); + if (current_tok->f_string_quote == quote && + current_tok->f_string_quote_size == quote_size) { + return MAKE_TOKEN(syntaxerror(tok, "f-string: expecting '}'", start)); + } + } + if (quote_size == 3) { syntaxerror(tok, "unterminated triple-quoted string literal" " (detected at line %d)", start); @@ -2089,6 +2337,27 @@ tok_get(struct tok_state *tok, struct token *token) goto again; /* Read next line */ } + /* Punctuation character */ + int is_punctuation = (c == ':' || c == '}' || c == '!' || c == '{'); + if (is_punctuation && tok->tok_mode_stack_index > 0 && current_tok->bracket_mark_index >= 0) { + int mark = *TOK_GET_BRACKET_MARK(current_tok); + /* This code block gets executed before the bracket_stack is incremented + * by the `{` case, so for ensuring that we are on the 0th level, we need + * to adjust it manually */ + int cursor = current_tok->bracket_stack - (c != '{'); + + if (cursor == 0 && !update_fstring_expr(tok, c)) { + return MAKE_TOKEN(ENDMARKER); + } + + if (c == ':' && cursor == mark) { + current_tok->kind = TOK_FSTRING_MODE; + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(_PyToken_OneChar(c)); + } + } + /* Check for two-character token */ { int c2 = tok_nextc(tok); @@ -2121,11 +2390,18 @@ tok_get(struct tok_state *tok, struct token *token) tok->parenlinenostack[tok->level] = tok->lineno; tok->parencolstack[tok->level] = (int)(tok->start - tok->line_start); tok->level++; + + if (tok->tok_mode_stack_index > 0) { + current_tok->bracket_stack++; + } break; case ')': case ']': case '}': if (!tok->level) { + if (tok->tok_mode_stack_index > 0 && !current_tok->bracket_stack && c == '}') { + return MAKE_TOKEN(syntaxerror(tok, "f-string: single '}' is not allowed")); + } return MAKE_TOKEN(syntaxerror(tok, "unmatched '%c'", c)); } tok->level--; @@ -2134,6 +2410,18 @@ tok_get(struct tok_state *tok, struct token *token) (opening == '[' && c == ']') || (opening == '{' && c == '}'))) { + /* If the opening bracket belongs to an f-string's expression + part (e.g. f"{)}") and the closing bracket is an arbitrary + nested expression, then instead of matching a different + syntactical construct with it; we'll throw an unmatched + parentheses error. */ + if (tok->tok_mode_stack_index > 0 && opening == '{') { + assert(current_tok->bracket_stack >= 0); + int previous_bracket = current_tok->bracket_stack - 1; + if (previous_bracket == *TOK_GET_BRACKET_MARK(current_tok)) { + return MAKE_TOKEN(syntaxerror(tok, "f-string: unmatched '%c'", c)); + } + } if (tok->parenlinenostack[tok->level] != tok->lineno) { return MAKE_TOKEN(syntaxerror(tok, "closing parenthesis '%c' does not match " @@ -2147,6 +2435,14 @@ tok_get(struct tok_state *tok, struct token *token) c, opening)); } } + + if (tok->tok_mode_stack_index > 0) { + current_tok->bracket_stack--; + if (c == '}' && current_tok->bracket_stack == *TOK_GET_BRACKET_MARK(current_tok)) { + current_tok->bracket_mark_index--; + current_tok->kind = TOK_FSTRING_MODE; + } + } break; } @@ -2162,6 +2458,187 @@ tok_get(struct tok_state *tok, struct token *token) return MAKE_TOKEN(_PyToken_OneChar(c)); } +static int +tok_get_fstring_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct token *token) +{ + const char *p_start = NULL; + const char *p_end = NULL; + int end_quote_size = 0; + int unicode_escape = 0; + + tok->start = tok->cur; + tok->first_lineno = tok->lineno; + tok->starting_col_offset = tok->col_offset; + + // If we start with a bracket, we defer to the normal mode as there is nothing for us to tokenize + // before it. + int start_char = tok_nextc(tok); + int peek1 = tok_nextc(tok); + tok_backup(tok, peek1); + tok_backup(tok, start_char); + + if ((start_char == '{' && peek1 != '{') || (start_char == '}' && peek1 != '}')) { + if (start_char == '{') { + current_tok->bracket_mark_index++; + if (current_tok->bracket_mark_index >= MAX_EXPR_NESTING) { + return MAKE_TOKEN(syntaxerror(tok, "f-string: expressions nested too deeply")); + } + *TOK_GET_BRACKET_MARK(current_tok) = current_tok->bracket_stack; + } + TOK_GET_MODE(tok)->kind = TOK_REGULAR_MODE; + return tok_get_normal_mode(tok, current_tok, token); + } + + // Check if we are at the end of the string + for (int i = 0; i < current_tok->f_string_quote_size; i++) { + int quote = tok_nextc(tok); + if (quote != current_tok->f_string_quote) { + tok_backup(tok, quote); + goto f_string_middle; + } + } + + if (current_tok->last_expr_buffer != NULL) { + PyMem_Free(current_tok->last_expr_buffer); + current_tok->last_expr_buffer = NULL; + current_tok->last_expr_size = 0; + current_tok->last_expr_end = -1; + } + + p_start = tok->start; + p_end = tok->cur; + tok->tok_mode_stack_index--; + return MAKE_TOKEN(FSTRING_END); + +f_string_middle: + + while (end_quote_size != current_tok->f_string_quote_size) { + int c = tok_nextc(tok); + if (c == EOF || (current_tok->f_string_quote_size == 1 && c == '\n')) { + assert(tok->multi_line_start != NULL); + // shift the tok_state's location into + // the start of string, and report the error + // from the initial quote character + tok->cur = (char *)current_tok->f_string_start; + tok->cur++; + tok->line_start = current_tok->f_string_multi_line_start; + int start = tok->lineno; + tok->lineno = tok->first_lineno; + + if (current_tok->f_string_quote_size == 3) { + return MAKE_TOKEN(syntaxerror(tok, + "unterminated triple-quoted f-string literal" + " (detected at line %d)", start)); + } + else { + return MAKE_TOKEN(syntaxerror(tok, + "unterminated f-string literal (detected at" + " line %d)", start)); + } + } + + if (c == current_tok->f_string_quote) { + end_quote_size += 1; + continue; + } else { + end_quote_size = 0; + } + + int in_format_spec = current_tok->last_expr_end != -1 && current_tok->bracket_mark_index >= 0; + if (c == '{') { + int peek = tok_nextc(tok); + if (peek != '{' || in_format_spec) { + tok_backup(tok, peek); + tok_backup(tok, c); + current_tok->bracket_mark_index++; + if (current_tok->bracket_mark_index >= MAX_EXPR_NESTING) { + return MAKE_TOKEN(syntaxerror(tok, "f-string: expressions nested too deeply")); + } + *TOK_GET_BRACKET_MARK(current_tok) = current_tok->bracket_stack; + TOK_GET_MODE(tok)->kind = TOK_REGULAR_MODE; + p_start = tok->start; + p_end = tok->cur; + } else { + p_start = tok->start; + p_end = tok->cur - 1; + } + return MAKE_TOKEN(FSTRING_MIDDLE); + } else if (c == '}') { + if (unicode_escape) { + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(FSTRING_MIDDLE); + } + int peek = tok_nextc(tok); + + // The tokenizer can only be in the format spec if we have already completed the expression + // scanning (indicated by the end of the expression being set) and we are not at the top level + // of the bracket stack (-1 is the top level). Since format specifiers can't legally use double + // brackets, we can bypass it here. + if (peek == '}' && !in_format_spec) { + p_start = tok->start; + p_end = tok->cur - 1; + } else { + tok_backup(tok, peek); + tok_backup(tok, c); + TOK_GET_MODE(tok)->kind = TOK_REGULAR_MODE; + p_start = tok->start; + p_end = tok->cur; + } + return MAKE_TOKEN(FSTRING_MIDDLE); + } else if (c == '\\') { + int peek = tok_nextc(tok); + // Special case when the backslash is right before a curly + // brace. We have to restore and return the control back + // to the loop for the next iteration. + if (peek == '{' || peek == '}') { + if (!current_tok->f_string_raw) { + if (warn_invalid_escape_sequence(tok, peek)) { + return MAKE_TOKEN(ERRORTOKEN); + } + } + tok_backup(tok, peek); + continue; + } + + if (!current_tok->f_string_raw) { + if (peek == 'N') { + /* Handle named unicode escapes (\N{BULLET}) */ + peek = tok_nextc(tok); + if (peek == '{') { + unicode_escape = 1; + } else { + tok_backup(tok, peek); + } + } + } /* else { + skip the escaped character + }*/ + } + } + + // Backup the f-string quotes to emit a final FSTRING_MIDDLE and + // add the quotes to the FSTRING_END in the next tokenizer iteration. + for (int i = 0; i < current_tok->f_string_quote_size; i++) { + tok_backup(tok, current_tok->f_string_quote); + } + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(FSTRING_MIDDLE); +} + + +static int +tok_get(struct tok_state *tok, struct token *token) +{ + tokenizer_mode *current_tok = TOK_GET_MODE(tok); + if (current_tok->kind == TOK_REGULAR_MODE) { + return tok_get_normal_mode(tok, current_tok, token); + } else { + return tok_get_fstring_mode(tok, current_tok, token); + } +} + int _PyTokenizer_Get(struct tok_state *tok, struct token *token) { diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h index 16a94d5f51d6..f67e0cd1ac2f 100644 --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -33,6 +33,31 @@ struct token { const char *start, *end; }; +enum tokenizer_mode_kind_t { + TOK_REGULAR_MODE, + TOK_FSTRING_MODE, +}; + +#define MAX_EXPR_NESTING 3 + +typedef struct _tokenizer_mode { + enum tokenizer_mode_kind_t kind; + + int bracket_stack; + int bracket_mark[MAX_EXPR_NESTING]; + int bracket_mark_index; + + char f_string_quote; + int f_string_quote_size; + int f_string_raw; + const char* f_string_start; + const char* f_string_multi_line_start; + + Py_ssize_t last_expr_size; + Py_ssize_t last_expr_end; + char* last_expr_buffer; +} tokenizer_mode; + /* Tokenizer state */ struct tok_state { /* Input state; buf <= cur <= inp <= end */ @@ -93,6 +118,10 @@ struct tok_state { /* How to proceed when asked for a new token in interactive mode */ enum interactive_underflow_t interactive_underflow; int report_warnings; + // TODO: Factor this into its own thing + tokenizer_mode tok_mode_stack[MAXLEVEL]; + int tok_mode_stack_index; + int tok_report_warnings; #ifdef Py_DEBUG int debug; #endif diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 4ac472a88261..cd9d1032629f 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -27,12 +27,12 @@ unsigned char M_test_frozenmain[] = { 218,3,107,101,121,169,0,243,0,0,0,0,250,18,116,101, 115,116,95,102,114,111,122,101,110,109,97,105,110,46,112,121, 250,8,60,109,111,100,117,108,101,62,114,18,0,0,0,1, - 0,0,0,115,100,0,0,0,240,3,1,1,1,243,8,0, + 0,0,0,115,102,0,0,0,240,3,1,1,1,243,8,0, 1,11,219,0,24,225,0,5,208,6,26,212,0,27,217,0, 5,128,106,144,35,151,40,145,40,212,0,27,216,9,38,208, 9,26,215,9,38,209,9,38,211,9,40,168,24,209,9,50, 128,6,240,2,6,12,2,242,0,7,1,42,128,67,241,14, - 0,5,10,208,10,40,144,67,209,10,40,152,54,160,35,153, - 59,209,10,40,213,4,41,241,15,7,1,42,114,16,0,0, - 0, + 0,5,10,136,71,144,67,144,53,152,2,152,54,160,35,153, + 59,152,45,208,10,40,213,4,41,241,15,7,1,42,114,16, + 0,0,0, }; diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index 8daa9877254e..416dc5971bca 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -86,8 +86,8 @@ tokenizeriter_next(tokenizeriterobject *it) Py_DECREF(str); return NULL; } - const char *line_start = type == STRING ? it->tok->multi_line_start : it->tok->line_start; - int lineno = type == STRING ? it->tok->first_lineno : it->tok->lineno; + const char *line_start = ISSTRINGLIT(type) ? it->tok->multi_line_start : it->tok->line_start; + int lineno = ISSTRINGLIT(type) ? it->tok->first_lineno : it->tok->lineno; int end_lineno = it->tok->lineno; int col_offset = -1; int end_col_offset = -1; diff --git a/Tools/build/generate_token.py b/Tools/build/generate_token.py index fc12835b7762..3bd307c17338 100755 --- a/Tools/build/generate_token.py +++ b/Tools/build/generate_token.py @@ -80,6 +80,8 @@ def update_file(file, content): (x) == NEWLINE || \\ (x) == INDENT || \\ (x) == DEDENT) +#define ISSTRINGLIT(x) ((x) == STRING || \\ + (x) == FSTRING_MIDDLE) // Symbols exported for test_peg_generator diff --git a/Tools/peg_generator/pegen/c_generator.py b/Tools/peg_generator/pegen/c_generator.py index e72ce7afdc47..f57b6275f671 100644 --- a/Tools/peg_generator/pegen/c_generator.py +++ b/Tools/peg_generator/pegen/c_generator.py @@ -68,6 +68,7 @@ class NodeTypes(Enum): KEYWORD = 4 SOFT_KEYWORD = 5 CUT_OPERATOR = 6 + F_STRING_CHUNK = 7 BASE_NODETYPES = { From webhook-mailer at python.org Wed Apr 19 13:53:41 2023 From: webhook-mailer at python.org (pablogsal) Date: Wed, 19 Apr 2023 17:53:41 -0000 Subject: [Python-checkins] gh-102856: Skip test_mismatched_parens in WASI builds (#103633) Message-ID: https://github.com/python/cpython/commit/5f7d68e48de19c5c3a241d7126fc2af227c2f74a commit: 5f7d68e48de19c5c3a241d7126fc2af227c2f74a branch: main author: Pablo Galindo Salgado committer: pablogsal date: 2023-04-19T11:53:34-06:00 summary: gh-102856: Skip test_mismatched_parens in WASI builds (#103633) files: M Lib/test/test_fstring.py diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index f571233da07b..0e71de85f16b 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -13,6 +13,7 @@ import types import decimal import unittest +from test import support from test.support.os_helper import temp_cwd from test.support.script_helper import assert_python_failure @@ -536,6 +537,7 @@ def test_unterminated_string(self): r"""f'{("x}'""", ]) + @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI") def test_mismatched_parens(self): self.assertAllRaise(SyntaxError, r"closing parenthesis '\}' " r"does not match opening parenthesis '\('", From webhook-mailer at python.org Wed Apr 19 16:51:38 2023 From: webhook-mailer at python.org (pablogsal) Date: Wed, 19 Apr 2023 20:51:38 -0000 Subject: [Python-checkins] gh-102856: Clean some of the PEP 701 tokenizer implementation (#103634) Message-ID: https://github.com/python/cpython/commit/d4aa8578b18d12380c841de96e8f80cac52bf61a commit: d4aa8578b18d12380c841de96e8f80cac52bf61a branch: main author: Pablo Galindo Salgado committer: pablogsal date: 2023-04-19T14:51:31-06:00 summary: gh-102856: Clean some of the PEP 701 tokenizer implementation (#103634) files: M Parser/tokenizer.c M Parser/tokenizer.h diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 1dfd2d6e5e17..f992e55dcac4 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -11,11 +11,6 @@ #include "tokenizer.h" #include "errcode.h" -#include "unicodeobject.h" -#include "bytesobject.h" -#include "fileobject.h" -#include "abstract.h" - /* Alternate tab spacing */ #define ALTTABSIZE 1 @@ -43,6 +38,8 @@ tok->lineno++; \ tok->col_offset = 0; +#define INSIDE_FSTRING(tok) (tok->tok_mode_stack_index > 0) +#define INSIDE_FSTRING_EXPR(tok) (tok->curly_bracket_expr_start_depth >= 0) #ifdef Py_DEBUG static inline tokenizer_mode* TOK_GET_MODE(struct tok_state* tok) { assert(tok->tok_mode_stack_index >= 0); @@ -54,15 +51,9 @@ static inline tokenizer_mode* TOK_NEXT_MODE(struct tok_state* tok) { assert(tok->tok_mode_stack_index < MAXLEVEL); return &(tok->tok_mode_stack[++tok->tok_mode_stack_index]); } -static inline int *TOK_GET_BRACKET_MARK(tokenizer_mode* mode) { - assert(mode->bracket_mark_index >= 0); - assert(mode->bracket_mark_index < MAX_EXPR_NESTING); - return &(mode->bracket_mark[mode->bracket_mark_index]); -} #else #define TOK_GET_MODE(tok) (&(tok->tok_mode_stack[tok->tok_mode_stack_index])) #define TOK_NEXT_MODE(tok) (&(tok->tok_mode_stack[++tok->tok_mode_stack_index])) -#define TOK_GET_BRACKET_MARK(mode) (&(mode->bracket_mark[mode->bracket_mark_index])) #endif /* Forward */ @@ -398,20 +389,7 @@ update_fstring_expr(struct tok_state *tok, char cur) tokenizer_mode *tok_mode = TOK_GET_MODE(tok); switch (cur) { - case '{': - if (tok_mode->last_expr_buffer != NULL) { - PyMem_Free(tok_mode->last_expr_buffer); - } - tok_mode->last_expr_buffer = PyMem_Malloc(size); - if (tok_mode->last_expr_buffer == NULL) { - tok->done = E_NOMEM; - return 0; - } - tok_mode->last_expr_size = size; - tok_mode->last_expr_end = -1; - strncpy(tok_mode->last_expr_buffer, tok->cur, size); - break; - case 0: + case 0: if (!tok_mode->last_expr_buffer || tok_mode->last_expr_end >= 0) { return 1; } @@ -421,13 +399,24 @@ update_fstring_expr(struct tok_state *tok, char cur) ); if (new_buffer == NULL) { PyMem_Free(tok_mode->last_expr_buffer); - tok->done = E_NOMEM; - return 0; + goto error; } tok_mode->last_expr_buffer = new_buffer; strncpy(tok_mode->last_expr_buffer + tok_mode->last_expr_size, tok->cur, size); tok_mode->last_expr_size += size; break; + case '{': + if (tok_mode->last_expr_buffer != NULL) { + PyMem_Free(tok_mode->last_expr_buffer); + } + tok_mode->last_expr_buffer = PyMem_Malloc(size); + if (tok_mode->last_expr_buffer == NULL) { + goto error; + } + tok_mode->last_expr_size = size; + tok_mode->last_expr_end = -1; + strncpy(tok_mode->last_expr_buffer, tok->cur, size); + break; case '}': case '!': case ':': @@ -435,9 +424,13 @@ update_fstring_expr(struct tok_state *tok, char cur) tok_mode->last_expr_end = strlen(tok->start); } break; + default: + Py_UNREACHABLE(); } - return 1; +error: + tok->done = E_NOMEM; + return 0; } static void @@ -1766,7 +1759,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t /* Skip comment, unless it's a type comment */ if (c == '#') { - if (tok->tok_mode_stack_index > 0) { + if (INSIDE_FSTRING(tok)) { return MAKE_TOKEN(syntaxerror(tok, "f-string expression part cannot include '#'")); } @@ -2208,32 +2201,31 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t p_start = tok->start; p_end = tok->cur; - tokenizer_mode *current_tok = TOK_NEXT_MODE(tok); - current_tok->kind = TOK_FSTRING_MODE; - current_tok->f_string_quote = quote; - current_tok->f_string_quote_size = quote_size; - current_tok->f_string_start = tok->start; - current_tok->f_string_multi_line_start = tok->line_start; - current_tok->last_expr_buffer = NULL; - current_tok->last_expr_size = 0; - current_tok->last_expr_end = -1; + tokenizer_mode *the_current_tok = TOK_NEXT_MODE(tok); + the_current_tok->kind = TOK_FSTRING_MODE; + the_current_tok->f_string_quote = quote; + the_current_tok->f_string_quote_size = quote_size; + the_current_tok->f_string_start = tok->start; + the_current_tok->f_string_multi_line_start = tok->line_start; + the_current_tok->last_expr_buffer = NULL; + the_current_tok->last_expr_size = 0; + the_current_tok->last_expr_end = -1; switch (*tok->start) { case 'F': case 'f': - current_tok->f_string_raw = tolower(*(tok->start + 1)) == 'r'; + the_current_tok->f_string_raw = tolower(*(tok->start + 1)) == 'r'; break; case 'R': case 'r': - current_tok->f_string_raw = 1; + the_current_tok->f_string_raw = 1; break; default: Py_UNREACHABLE(); } - current_tok->bracket_stack = 0; - current_tok->bracket_mark[0] = 0; - current_tok->bracket_mark_index = -1; + the_current_tok->curly_bracket_depth = 0; + the_current_tok->curly_bracket_expr_start_depth = -1; return MAKE_TOKEN(FSTRING_START); } @@ -2282,15 +2274,15 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t int start = tok->lineno; tok->lineno = tok->first_lineno; - if (tok->tok_mode_stack_index > 0) { + if (INSIDE_FSTRING(tok)) { /* When we are in an f-string, before raising the * unterminated string literal error, check whether * does the initial quote matches with f-strings quotes * and if it is, then this must be a missing '}' token * so raise the proper error */ - tokenizer_mode *current_tok = TOK_GET_MODE(tok); - if (current_tok->f_string_quote == quote && - current_tok->f_string_quote_size == quote_size) { + tokenizer_mode *the_current_tok = TOK_GET_MODE(tok); + if (the_current_tok->f_string_quote == quote && + the_current_tok->f_string_quote_size == quote_size) { return MAKE_TOKEN(syntaxerror(tok, "f-string: expecting '}'", start)); } } @@ -2339,18 +2331,17 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t /* Punctuation character */ int is_punctuation = (c == ':' || c == '}' || c == '!' || c == '{'); - if (is_punctuation && tok->tok_mode_stack_index > 0 && current_tok->bracket_mark_index >= 0) { - int mark = *TOK_GET_BRACKET_MARK(current_tok); - /* This code block gets executed before the bracket_stack is incremented + if (is_punctuation && INSIDE_FSTRING(tok) && INSIDE_FSTRING_EXPR(current_tok)) { + /* This code block gets executed before the curly_bracket_depth is incremented * by the `{` case, so for ensuring that we are on the 0th level, we need * to adjust it manually */ - int cursor = current_tok->bracket_stack - (c != '{'); + int cursor = current_tok->curly_bracket_depth - (c != '{'); if (cursor == 0 && !update_fstring_expr(tok, c)) { return MAKE_TOKEN(ENDMARKER); } - if (c == ':' && cursor == mark) { + if (c == ':' && cursor == current_tok->curly_bracket_expr_start_depth) { current_tok->kind = TOK_FSTRING_MODE; p_start = tok->start; p_end = tok->cur; @@ -2390,16 +2381,15 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t tok->parenlinenostack[tok->level] = tok->lineno; tok->parencolstack[tok->level] = (int)(tok->start - tok->line_start); tok->level++; - - if (tok->tok_mode_stack_index > 0) { - current_tok->bracket_stack++; + if (INSIDE_FSTRING(tok)) { + current_tok->curly_bracket_depth++; } break; case ')': case ']': case '}': if (!tok->level) { - if (tok->tok_mode_stack_index > 0 && !current_tok->bracket_stack && c == '}') { + if (INSIDE_FSTRING(tok) && !current_tok->curly_bracket_depth && c == '}') { return MAKE_TOKEN(syntaxerror(tok, "f-string: single '}' is not allowed")); } return MAKE_TOKEN(syntaxerror(tok, "unmatched '%c'", c)); @@ -2415,10 +2405,10 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t nested expression, then instead of matching a different syntactical construct with it; we'll throw an unmatched parentheses error. */ - if (tok->tok_mode_stack_index > 0 && opening == '{') { - assert(current_tok->bracket_stack >= 0); - int previous_bracket = current_tok->bracket_stack - 1; - if (previous_bracket == *TOK_GET_BRACKET_MARK(current_tok)) { + if (INSIDE_FSTRING(tok) && opening == '{') { + assert(current_tok->curly_bracket_depth >= 0); + int previous_bracket = current_tok->curly_bracket_depth - 1; + if (previous_bracket == current_tok->curly_bracket_expr_start_depth) { return MAKE_TOKEN(syntaxerror(tok, "f-string: unmatched '%c'", c)); } } @@ -2436,14 +2426,16 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t } } - if (tok->tok_mode_stack_index > 0) { - current_tok->bracket_stack--; - if (c == '}' && current_tok->bracket_stack == *TOK_GET_BRACKET_MARK(current_tok)) { - current_tok->bracket_mark_index--; + if (INSIDE_FSTRING(tok)) { + current_tok->curly_bracket_depth--; + if (c == '}' && current_tok->curly_bracket_depth == current_tok->curly_bracket_expr_start_depth) { + current_tok->curly_bracket_expr_start_depth--; current_tok->kind = TOK_FSTRING_MODE; } } break; + default: + break; } if (!Py_UNICODE_ISPRINTABLE(c)) { @@ -2479,11 +2471,10 @@ tok_get_fstring_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct if ((start_char == '{' && peek1 != '{') || (start_char == '}' && peek1 != '}')) { if (start_char == '{') { - current_tok->bracket_mark_index++; - if (current_tok->bracket_mark_index >= MAX_EXPR_NESTING) { + current_tok->curly_bracket_expr_start_depth++; + if (current_tok->curly_bracket_expr_start_depth >= MAX_EXPR_NESTING) { return MAKE_TOKEN(syntaxerror(tok, "f-string: expressions nested too deeply")); } - *TOK_GET_BRACKET_MARK(current_tok) = current_tok->bracket_stack; } TOK_GET_MODE(tok)->kind = TOK_REGULAR_MODE; return tok_get_normal_mode(tok, current_tok, token); @@ -2544,17 +2535,20 @@ tok_get_fstring_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct end_quote_size = 0; } - int in_format_spec = current_tok->last_expr_end != -1 && current_tok->bracket_mark_index >= 0; + int in_format_spec = ( + current_tok->last_expr_end != -1 + && + INSIDE_FSTRING_EXPR(current_tok) + ); if (c == '{') { int peek = tok_nextc(tok); if (peek != '{' || in_format_spec) { tok_backup(tok, peek); tok_backup(tok, c); - current_tok->bracket_mark_index++; - if (current_tok->bracket_mark_index >= MAX_EXPR_NESTING) { + current_tok->curly_bracket_expr_start_depth++; + if (current_tok->curly_bracket_expr_start_depth >= MAX_EXPR_NESTING) { return MAKE_TOKEN(syntaxerror(tok, "f-string: expressions nested too deeply")); } - *TOK_GET_BRACKET_MARK(current_tok) = current_tok->bracket_stack; TOK_GET_MODE(tok)->kind = TOK_REGULAR_MODE; p_start = tok->start; p_end = tok->cur; diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h index f67e0cd1ac2f..b75e4e8293d3 100644 --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -43,9 +43,8 @@ enum tokenizer_mode_kind_t { typedef struct _tokenizer_mode { enum tokenizer_mode_kind_t kind; - int bracket_stack; - int bracket_mark[MAX_EXPR_NESTING]; - int bracket_mark_index; + int curly_bracket_depth; + int curly_bracket_expr_start_depth; char f_string_quote; int f_string_quote_size; From webhook-mailer at python.org Wed Apr 19 17:02:36 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 19 Apr 2023 21:02:36 -0000 Subject: [Python-checkins] gh-83861: Fix datetime.astimezone() method (GH-101545) Message-ID: https://github.com/python/cpython/commit/2b1260c55763a952c57b92fe0f274b6ee79efd05 commit: 2b1260c55763a952c57b92fe0f274b6ee79efd05 branch: main author: Alexander Belopolsky committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-04-19T14:02:29-07:00 summary: gh-83861: Fix datetime.astimezone() method (GH-101545) files: A Misc/NEWS.d/next/Library/2023-02-06-16-45-18.gh-issue-83861.mMbIU3.rst M Lib/datetime.py M Lib/test/datetimetester.py M Modules/_datetimemodule.c diff --git a/Lib/datetime.py b/Lib/datetime.py index 637144637485..09a2d2d5381c 100644 --- a/Lib/datetime.py +++ b/Lib/datetime.py @@ -1965,6 +1965,11 @@ def replace(self, year=None, month=None, day=None, hour=None, def _local_timezone(self): if self.tzinfo is None: ts = self._mktime() + # Detect gap + ts2 = self.replace(fold=1-self.fold)._mktime() + if ts2 != ts: # This happens in a gap or a fold + if (ts2 > ts) == self.fold: + ts = ts2 else: ts = (self - _EPOCH) // timedelta(seconds=1) localtm = _time.localtime(ts) diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index 570f803918c1..477f16f1841f 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -6212,6 +6212,10 @@ def test_system_transitions(self): ts1 = dt.replace(fold=1).timestamp() self.assertEqual(ts0, s0 + ss / 2) self.assertEqual(ts1, s0 - ss / 2) + # gh-83861 + utc0 = dt.astimezone(timezone.utc) + utc1 = dt.replace(fold=1).astimezone(timezone.utc) + self.assertEqual(utc0, utc1 + timedelta(0, ss)) finally: if TZ is None: del os.environ['TZ'] diff --git a/Misc/NEWS.d/next/Library/2023-02-06-16-45-18.gh-issue-83861.mMbIU3.rst b/Misc/NEWS.d/next/Library/2023-02-06-16-45-18.gh-issue-83861.mMbIU3.rst new file mode 100644 index 000000000000..e85e7a4ff2e7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-06-16-45-18.gh-issue-83861.mMbIU3.rst @@ -0,0 +1,4 @@ +Fix datetime.astimezone method return value when invoked on a naive datetime +instance that represents local time falling in a timezone transition gap. +PEP 495 requires that instances with fold=1 produce earlier times than those +with fold=0 in this case. diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index eda8c5610ba6..f317dc14e15b 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6153,17 +6153,31 @@ local_to_seconds(int year, int month, int day, static PyObject * local_timezone_from_local(PyDateTime_DateTime *local_dt) { - long long seconds; + long long seconds, seconds2; time_t timestamp; + int fold = DATE_GET_FOLD(local_dt); seconds = local_to_seconds(GET_YEAR(local_dt), GET_MONTH(local_dt), GET_DAY(local_dt), DATE_GET_HOUR(local_dt), DATE_GET_MINUTE(local_dt), DATE_GET_SECOND(local_dt), - DATE_GET_FOLD(local_dt)); + fold); if (seconds == -1) return NULL; + seconds2 = local_to_seconds(GET_YEAR(local_dt), + GET_MONTH(local_dt), + GET_DAY(local_dt), + DATE_GET_HOUR(local_dt), + DATE_GET_MINUTE(local_dt), + DATE_GET_SECOND(local_dt), + !fold); + if (seconds2 == -1) + return NULL; + /* Detect gap */ + if (seconds2 != seconds && (seconds2 > seconds) == fold) + seconds = seconds2; + /* XXX: add bounds check */ timestamp = seconds - epoch; return local_timezone_from_timestamp(timestamp); From webhook-mailer at python.org Wed Apr 19 18:09:45 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Wed, 19 Apr 2023 22:09:45 -0000 Subject: [Python-checkins] gh-98040: Move the Single-Phase Init Tests Out of test_imp (gh-102561) Message-ID: https://github.com/python/cpython/commit/6be7aee18c5b8e639103df951d0d277f4b46f902 commit: 6be7aee18c5b8e639103df951d0d277f4b46f902 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-04-19T16:09:35-06:00 summary: gh-98040: Move the Single-Phase Init Tests Out of test_imp (gh-102561) I recently added some tests to test_imp, but @warsaw is removing that file in gh-98573. The tests are worth keeping so here I'm moving them to test_import. files: M Lib/test/test_imp.py M Lib/test/test_import/__init__.py diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py index 03e3adba221e..80abc720c325 100644 --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -1,5 +1,4 @@ import gc -import json import importlib import importlib.util import os @@ -11,28 +10,15 @@ from test.support import os_helper from test.support import script_helper from test.support import warnings_helper -import textwrap -import types import unittest import warnings imp = warnings_helper.import_deprecated('imp') import _imp -import _testinternalcapi -try: - import _xxsubinterpreters as _interpreters -except ModuleNotFoundError: - _interpreters = None OS_PATH_NAME = os.path.__name__ -def requires_subinterpreters(meth): - """Decorator to skip a test if subinterpreters are not supported.""" - return unittest.skipIf(_interpreters is None, - 'subinterpreters required')(meth) - - def requires_load_dynamic(meth): """Decorator to skip a test if not running under CPython or lacking imp.load_dynamic().""" @@ -41,169 +27,6 @@ def requires_load_dynamic(meth): 'imp.load_dynamic() required')(meth) -class ModuleSnapshot(types.SimpleNamespace): - """A representation of a module for testing. - - Fields: - - * id - the module's object ID - * module - the actual module or an adequate substitute - * __file__ - * __spec__ - * name - * origin - * ns - a copy (dict) of the module's __dict__ (or None) - * ns_id - the object ID of the module's __dict__ - * cached - the sys.modules[mod.__spec__.name] entry (or None) - * cached_id - the object ID of the sys.modules entry (or None) - - In cases where the value is not available (e.g. due to serialization), - the value will be None. - """ - _fields = tuple('id module ns ns_id cached cached_id'.split()) - - @classmethod - def from_module(cls, mod): - name = mod.__spec__.name - cached = sys.modules.get(name) - return cls( - id=id(mod), - module=mod, - ns=types.SimpleNamespace(**mod.__dict__), - ns_id=id(mod.__dict__), - cached=cached, - cached_id=id(cached), - ) - - SCRIPT = textwrap.dedent(''' - {imports} - - name = {name!r} - - {prescript} - - mod = {name} - - {body} - - {postscript} - ''') - IMPORTS = textwrap.dedent(''' - import sys - ''').strip() - SCRIPT_BODY = textwrap.dedent(''' - # Capture the snapshot data. - cached = sys.modules.get(name) - snapshot = dict( - id=id(mod), - module=dict( - __file__=mod.__file__, - __spec__=dict( - name=mod.__spec__.name, - origin=mod.__spec__.origin, - ), - ), - ns=None, - ns_id=id(mod.__dict__), - cached=None, - cached_id=id(cached) if cached else None, - ) - ''').strip() - CLEANUP_SCRIPT = textwrap.dedent(''' - # Clean up the module. - sys.modules.pop(name, None) - ''').strip() - - @classmethod - def build_script(cls, name, *, - prescript=None, - import_first=False, - postscript=None, - postcleanup=False, - ): - if postcleanup is True: - postcleanup = cls.CLEANUP_SCRIPT - elif isinstance(postcleanup, str): - postcleanup = textwrap.dedent(postcleanup).strip() - postcleanup = cls.CLEANUP_SCRIPT + os.linesep + postcleanup - else: - postcleanup = '' - prescript = textwrap.dedent(prescript).strip() if prescript else '' - postscript = textwrap.dedent(postscript).strip() if postscript else '' - - if postcleanup: - if postscript: - postscript = postscript + os.linesep * 2 + postcleanup - else: - postscript = postcleanup - - if import_first: - prescript += textwrap.dedent(f''' - - # Now import the module. - assert name not in sys.modules - import {name}''') - - return cls.SCRIPT.format( - imports=cls.IMPORTS.strip(), - name=name, - prescript=prescript.strip(), - body=cls.SCRIPT_BODY.strip(), - postscript=postscript, - ) - - @classmethod - def parse(cls, text): - raw = json.loads(text) - mod = raw['module'] - mod['__spec__'] = types.SimpleNamespace(**mod['__spec__']) - raw['module'] = types.SimpleNamespace(**mod) - return cls(**raw) - - @classmethod - def from_subinterp(cls, name, interpid=None, *, pipe=None, **script_kwds): - if pipe is not None: - return cls._from_subinterp(name, interpid, pipe, script_kwds) - pipe = os.pipe() - try: - return cls._from_subinterp(name, interpid, pipe, script_kwds) - finally: - r, w = pipe - os.close(r) - os.close(w) - - @classmethod - def _from_subinterp(cls, name, interpid, pipe, script_kwargs): - r, w = pipe - - # Build the script. - postscript = textwrap.dedent(f''' - # Send the result over the pipe. - import json - import os - os.write({w}, json.dumps(snapshot).encode()) - - ''') - _postscript = script_kwargs.get('postscript') - if _postscript: - _postscript = textwrap.dedent(_postscript).lstrip() - postscript += _postscript - script_kwargs['postscript'] = postscript.strip() - script = cls.build_script(name, **script_kwargs) - - # Run the script. - if interpid is None: - ret = support.run_in_subinterp(script) - if ret != 0: - raise AssertionError(f'{ret} != 0') - else: - _interpreters.run_string(interpid, script) - - # Parse the results. - text = os.read(r, 1000) - return cls.parse(text.decode()) - - class LockTests(unittest.TestCase): """Very basic test of import lock functions.""" @@ -620,669 +443,6 @@ def check_get_builtins(): check_get_builtins() -class TestSinglePhaseSnapshot(ModuleSnapshot): - - @classmethod - def from_module(cls, mod): - self = super().from_module(mod) - self.summed = mod.sum(1, 2) - self.lookedup = mod.look_up_self() - self.lookedup_id = id(self.lookedup) - self.state_initialized = mod.state_initialized() - if hasattr(mod, 'initialized_count'): - self.init_count = mod.initialized_count() - return self - - SCRIPT_BODY = ModuleSnapshot.SCRIPT_BODY + textwrap.dedent(f''' - snapshot['module'].update(dict( - int_const=mod.int_const, - str_const=mod.str_const, - _module_initialized=mod._module_initialized, - )) - snapshot.update(dict( - summed=mod.sum(1, 2), - lookedup_id=id(mod.look_up_self()), - state_initialized=mod.state_initialized(), - init_count=mod.initialized_count(), - has_spam=hasattr(mod, 'spam'), - spam=getattr(mod, 'spam', None), - )) - ''').rstrip() - - @classmethod - def parse(cls, text): - self = super().parse(text) - if not self.has_spam: - del self.spam - del self.has_spam - return self - - - at requires_load_dynamic -class SinglephaseInitTests(unittest.TestCase): - - NAME = '_testsinglephase' - - @classmethod - def setUpClass(cls): - if '-R' in sys.argv or '--huntrleaks' in sys.argv: - # https://github.com/python/cpython/issues/102251 - raise unittest.SkipTest('unresolved refleaks (see gh-102251)') - fileobj, filename, _ = imp.find_module(cls.NAME) - fileobj.close() - cls.FILE = filename - - # Start fresh. - cls.clean_up() - - def tearDown(self): - # Clean up the module. - self.clean_up() - - @classmethod - def clean_up(cls): - name = cls.NAME - filename = cls.FILE - if name in sys.modules: - if hasattr(sys.modules[name], '_clear_globals'): - assert sys.modules[name].__file__ == filename - sys.modules[name]._clear_globals() - del sys.modules[name] - # Clear all internally cached data for the extension. - _testinternalcapi.clear_extension(name, filename) - - ######################### - # helpers - - def add_module_cleanup(self, name): - def clean_up(): - # Clear all internally cached data for the extension. - _testinternalcapi.clear_extension(name, self.FILE) - self.addCleanup(clean_up) - - def load(self, name): - try: - already_loaded = self.already_loaded - except AttributeError: - already_loaded = self.already_loaded = {} - assert name not in already_loaded - mod = imp.load_dynamic(name, self.FILE) - self.assertNotIn(mod, already_loaded.values()) - already_loaded[name] = mod - return types.SimpleNamespace( - name=name, - module=mod, - snapshot=TestSinglePhaseSnapshot.from_module(mod), - ) - - def re_load(self, name, mod): - assert sys.modules[name] is mod - assert mod.__dict__ == mod.__dict__ - reloaded = imp.load_dynamic(name, self.FILE) - return types.SimpleNamespace( - name=name, - module=reloaded, - snapshot=TestSinglePhaseSnapshot.from_module(reloaded), - ) - - # subinterpreters - - def add_subinterpreter(self): - interpid = _interpreters.create(isolated=False) - _interpreters.run_string(interpid, textwrap.dedent(''' - import sys - import _testinternalcapi - ''')) - def clean_up(): - _interpreters.run_string(interpid, textwrap.dedent(f''' - name = {self.NAME!r} - if name in sys.modules: - sys.modules[name]._clear_globals() - _testinternalcapi.clear_extension(name, {self.FILE!r}) - ''')) - _interpreters.destroy(interpid) - self.addCleanup(clean_up) - return interpid - - def import_in_subinterp(self, interpid=None, *, - postscript=None, - postcleanup=False, - ): - name = self.NAME - - if postcleanup: - import_ = 'import _testinternalcapi' if interpid is None else '' - postcleanup = f''' - {import_} - mod._clear_globals() - _testinternalcapi.clear_extension(name, {self.FILE!r}) - ''' - - try: - pipe = self._pipe - except AttributeError: - r, w = pipe = self._pipe = os.pipe() - self.addCleanup(os.close, r) - self.addCleanup(os.close, w) - - snapshot = TestSinglePhaseSnapshot.from_subinterp( - name, - interpid, - pipe=pipe, - import_first=True, - postscript=postscript, - postcleanup=postcleanup, - ) - - return types.SimpleNamespace( - name=name, - module=None, - snapshot=snapshot, - ) - - # checks - - def check_common(self, loaded): - isolated = False - - mod = loaded.module - if not mod: - # It came from a subinterpreter. - isolated = True - mod = loaded.snapshot.module - # mod.__name__ might not match, but the spec will. - self.assertEqual(mod.__spec__.name, loaded.name) - self.assertEqual(mod.__file__, self.FILE) - self.assertEqual(mod.__spec__.origin, self.FILE) - if not isolated: - self.assertTrue(issubclass(mod.error, Exception)) - self.assertEqual(mod.int_const, 1969) - self.assertEqual(mod.str_const, 'something different') - self.assertIsInstance(mod._module_initialized, float) - self.assertGreater(mod._module_initialized, 0) - - snap = loaded.snapshot - self.assertEqual(snap.summed, 3) - if snap.state_initialized is not None: - self.assertIsInstance(snap.state_initialized, float) - self.assertGreater(snap.state_initialized, 0) - if isolated: - # The "looked up" module is interpreter-specific - # (interp->imports.modules_by_index was set for the module). - self.assertEqual(snap.lookedup_id, snap.id) - self.assertEqual(snap.cached_id, snap.id) - with self.assertRaises(AttributeError): - snap.spam - else: - self.assertIs(snap.lookedup, mod) - self.assertIs(snap.cached, mod) - - def check_direct(self, loaded): - # The module has its own PyModuleDef, with a matching name. - self.assertEqual(loaded.module.__name__, loaded.name) - self.assertIs(loaded.snapshot.lookedup, loaded.module) - - def check_indirect(self, loaded, orig): - # The module re-uses another's PyModuleDef, with a different name. - assert orig is not loaded.module - assert orig.__name__ != loaded.name - self.assertNotEqual(loaded.module.__name__, loaded.name) - self.assertIs(loaded.snapshot.lookedup, loaded.module) - - def check_basic(self, loaded, expected_init_count): - # m_size == -1 - # The module loads fresh the first time and copies m_copy after. - snap = loaded.snapshot - self.assertIsNot(snap.state_initialized, None) - self.assertIsInstance(snap.init_count, int) - self.assertGreater(snap.init_count, 0) - self.assertEqual(snap.init_count, expected_init_count) - - def check_with_reinit(self, loaded): - # m_size >= 0 - # The module loads fresh every time. - pass - - def check_fresh(self, loaded): - """ - The module had not been loaded before (at least since fully reset). - """ - snap = loaded.snapshot - # The module's init func was run. - # A copy of the module's __dict__ was stored in def->m_base.m_copy. - # The previous m_copy was deleted first. - # _PyRuntime.imports.extensions was set. - self.assertEqual(snap.init_count, 1) - # The global state was initialized. - # The module attrs were initialized from that state. - self.assertEqual(snap.module._module_initialized, - snap.state_initialized) - - def check_semi_fresh(self, loaded, base, prev): - """ - The module had been loaded before and then reset - (but the module global state wasn't). - """ - snap = loaded.snapshot - # The module's init func was run again. - # A copy of the module's __dict__ was stored in def->m_base.m_copy. - # The previous m_copy was deleted first. - # The module globals did not get reset. - self.assertNotEqual(snap.id, base.snapshot.id) - self.assertNotEqual(snap.id, prev.snapshot.id) - self.assertEqual(snap.init_count, prev.snapshot.init_count + 1) - # The global state was updated. - # The module attrs were initialized from that state. - self.assertEqual(snap.module._module_initialized, - snap.state_initialized) - self.assertNotEqual(snap.state_initialized, - base.snapshot.state_initialized) - self.assertNotEqual(snap.state_initialized, - prev.snapshot.state_initialized) - - def check_copied(self, loaded, base): - """ - The module had been loaded before and never reset. - """ - snap = loaded.snapshot - # The module's init func was not run again. - # The interpreter copied m_copy, as set by the other interpreter, - # with objects owned by the other interpreter. - # The module globals did not get reset. - self.assertNotEqual(snap.id, base.snapshot.id) - self.assertEqual(snap.init_count, base.snapshot.init_count) - # The global state was not updated since the init func did not run. - # The module attrs were not directly initialized from that state. - # The state and module attrs still match the previous loading. - self.assertEqual(snap.module._module_initialized, - snap.state_initialized) - self.assertEqual(snap.state_initialized, - base.snapshot.state_initialized) - - ######################### - # the tests - - def test_cleared_globals(self): - loaded = self.load(self.NAME) - _testsinglephase = loaded.module - init_before = _testsinglephase.state_initialized() - - _testsinglephase._clear_globals() - init_after = _testsinglephase.state_initialized() - init_count = _testsinglephase.initialized_count() - - self.assertGreater(init_before, 0) - self.assertEqual(init_after, 0) - self.assertEqual(init_count, -1) - - def test_variants(self): - # Exercise the most meaningful variants described in Python/import.c. - self.maxDiff = None - - # Check the "basic" module. - - name = self.NAME - expected_init_count = 1 - with self.subTest(name): - loaded = self.load(name) - - self.check_common(loaded) - self.check_direct(loaded) - self.check_basic(loaded, expected_init_count) - basic = loaded.module - - # Check its indirect variants. - - name = f'{self.NAME}_basic_wrapper' - self.add_module_cleanup(name) - expected_init_count += 1 - with self.subTest(name): - loaded = self.load(name) - - self.check_common(loaded) - self.check_indirect(loaded, basic) - self.check_basic(loaded, expected_init_count) - - # Currently PyState_AddModule() always replaces the cached module. - self.assertIs(basic.look_up_self(), loaded.module) - self.assertEqual(basic.initialized_count(), expected_init_count) - - # The cached module shouldn't change after this point. - basic_lookedup = loaded.module - - # Check its direct variant. - - name = f'{self.NAME}_basic_copy' - self.add_module_cleanup(name) - expected_init_count += 1 - with self.subTest(name): - loaded = self.load(name) - - self.check_common(loaded) - self.check_direct(loaded) - self.check_basic(loaded, expected_init_count) - - # This should change the cached module for _testsinglephase. - self.assertIs(basic.look_up_self(), basic_lookedup) - self.assertEqual(basic.initialized_count(), expected_init_count) - - # Check the non-basic variant that has no state. - - name = f'{self.NAME}_with_reinit' - self.add_module_cleanup(name) - with self.subTest(name): - loaded = self.load(name) - - self.check_common(loaded) - self.assertIs(loaded.snapshot.state_initialized, None) - self.check_direct(loaded) - self.check_with_reinit(loaded) - - # This should change the cached module for _testsinglephase. - self.assertIs(basic.look_up_self(), basic_lookedup) - self.assertEqual(basic.initialized_count(), expected_init_count) - - # Check the basic variant that has state. - - name = f'{self.NAME}_with_state' - self.add_module_cleanup(name) - with self.subTest(name): - loaded = self.load(name) - - self.check_common(loaded) - self.assertIsNot(loaded.snapshot.state_initialized, None) - self.check_direct(loaded) - self.check_with_reinit(loaded) - - # This should change the cached module for _testsinglephase. - self.assertIs(basic.look_up_self(), basic_lookedup) - self.assertEqual(basic.initialized_count(), expected_init_count) - - def test_basic_reloaded(self): - # m_copy is copied into the existing module object. - # Global state is not changed. - self.maxDiff = None - - for name in [ - self.NAME, # the "basic" module - f'{self.NAME}_basic_wrapper', # the indirect variant - f'{self.NAME}_basic_copy', # the direct variant - ]: - self.add_module_cleanup(name) - with self.subTest(name): - loaded = self.load(name) - reloaded = self.re_load(name, loaded.module) - - self.check_common(loaded) - self.check_common(reloaded) - - # Make sure the original __dict__ did not get replaced. - self.assertEqual(id(loaded.module.__dict__), - loaded.snapshot.ns_id) - self.assertEqual(loaded.snapshot.ns.__dict__, - loaded.module.__dict__) - - self.assertEqual(reloaded.module.__spec__.name, reloaded.name) - self.assertEqual(reloaded.module.__name__, - reloaded.snapshot.ns.__name__) - - self.assertIs(reloaded.module, loaded.module) - self.assertIs(reloaded.module.__dict__, loaded.module.__dict__) - # It only happens to be the same but that's good enough here. - # We really just want to verify that the re-loaded attrs - # didn't change. - self.assertIs(reloaded.snapshot.lookedup, - loaded.snapshot.lookedup) - self.assertEqual(reloaded.snapshot.state_initialized, - loaded.snapshot.state_initialized) - self.assertEqual(reloaded.snapshot.init_count, - loaded.snapshot.init_count) - - self.assertIs(reloaded.snapshot.cached, reloaded.module) - - def test_with_reinit_reloaded(self): - # The module's m_init func is run again. - self.maxDiff = None - - # Keep a reference around. - basic = self.load(self.NAME) - - for name in [ - f'{self.NAME}_with_reinit', # m_size == 0 - f'{self.NAME}_with_state', # m_size > 0 - ]: - self.add_module_cleanup(name) - with self.subTest(name): - loaded = self.load(name) - reloaded = self.re_load(name, loaded.module) - - self.check_common(loaded) - self.check_common(reloaded) - - # Make sure the original __dict__ did not get replaced. - self.assertEqual(id(loaded.module.__dict__), - loaded.snapshot.ns_id) - self.assertEqual(loaded.snapshot.ns.__dict__, - loaded.module.__dict__) - - self.assertEqual(reloaded.module.__spec__.name, reloaded.name) - self.assertEqual(reloaded.module.__name__, - reloaded.snapshot.ns.__name__) - - self.assertIsNot(reloaded.module, loaded.module) - self.assertNotEqual(reloaded.module.__dict__, - loaded.module.__dict__) - self.assertIs(reloaded.snapshot.lookedup, reloaded.module) - if loaded.snapshot.state_initialized is None: - self.assertIs(reloaded.snapshot.state_initialized, None) - else: - self.assertGreater(reloaded.snapshot.state_initialized, - loaded.snapshot.state_initialized) - - self.assertIs(reloaded.snapshot.cached, reloaded.module) - - # Currently, for every single-phrase init module loaded - # in multiple interpreters, those interpreters share a - # PyModuleDef for that object, which can be a problem. - # Also, we test with a single-phase module that has global state, - # which is shared by all interpreters. - - @requires_subinterpreters - def test_basic_multiple_interpreters_main_no_reset(self): - # without resetting; already loaded in main interpreter - - # At this point: - # * alive in 0 interpreters - # * module def may or may not be loaded already - # * module def not in _PyRuntime.imports.extensions - # * mod init func has not run yet (since reset, at least) - # * m_copy not set (hasn't been loaded yet or already cleared) - # * module's global state has not been initialized yet - # (or already cleared) - - main_loaded = self.load(self.NAME) - _testsinglephase = main_loaded.module - # Attrs set after loading are not in m_copy. - _testsinglephase.spam = 'spam, spam, spam, spam, eggs, and spam' - - self.check_common(main_loaded) - self.check_fresh(main_loaded) - - interpid1 = self.add_subinterpreter() - interpid2 = self.add_subinterpreter() - - # At this point: - # * alive in 1 interpreter (main) - # * module def in _PyRuntime.imports.extensions - # * mod init func ran for the first time (since reset, at least) - # * m_copy was copied from the main interpreter (was NULL) - # * module's global state was initialized - - # Use an interpreter that gets destroyed right away. - loaded = self.import_in_subinterp() - self.check_common(loaded) - self.check_copied(loaded, main_loaded) - - # At this point: - # * alive in 1 interpreter (main) - # * module def still in _PyRuntime.imports.extensions - # * mod init func ran again - # * m_copy is NULL (claered when the interpreter was destroyed) - # (was from main interpreter) - # * module's global state was updated, not reset - - # Use a subinterpreter that sticks around. - loaded = self.import_in_subinterp(interpid1) - self.check_common(loaded) - self.check_copied(loaded, main_loaded) - - # At this point: - # * alive in 2 interpreters (main, interp1) - # * module def still in _PyRuntime.imports.extensions - # * mod init func ran again - # * m_copy was copied from interp1 - # * module's global state was updated, not reset - - # Use a subinterpreter while the previous one is still alive. - loaded = self.import_in_subinterp(interpid2) - self.check_common(loaded) - self.check_copied(loaded, main_loaded) - - # At this point: - # * alive in 3 interpreters (main, interp1, interp2) - # * module def still in _PyRuntime.imports.extensions - # * mod init func ran again - # * m_copy was copied from interp2 (was from interp1) - # * module's global state was updated, not reset - - @requires_subinterpreters - def test_basic_multiple_interpreters_deleted_no_reset(self): - # without resetting; already loaded in a deleted interpreter - - # At this point: - # * alive in 0 interpreters - # * module def may or may not be loaded already - # * module def not in _PyRuntime.imports.extensions - # * mod init func has not run yet (since reset, at least) - # * m_copy not set (hasn't been loaded yet or already cleared) - # * module's global state has not been initialized yet - # (or already cleared) - - interpid1 = self.add_subinterpreter() - interpid2 = self.add_subinterpreter() - - # First, load in the main interpreter but then completely clear it. - loaded_main = self.load(self.NAME) - loaded_main.module._clear_globals() - _testinternalcapi.clear_extension(self.NAME, self.FILE) - - # At this point: - # * alive in 0 interpreters - # * module def loaded already - # * module def was in _PyRuntime.imports.extensions, but cleared - # * mod init func ran for the first time (since reset, at least) - # * m_copy was set, but cleared (was NULL) - # * module's global state was initialized but cleared - - # Start with an interpreter that gets destroyed right away. - base = self.import_in_subinterp(postscript=''' - # Attrs set after loading are not in m_copy. - mod.spam = 'spam, spam, mash, spam, eggs, and spam' - ''') - self.check_common(base) - self.check_fresh(base) - - # At this point: - # * alive in 0 interpreters - # * module def in _PyRuntime.imports.extensions - # * mod init func ran again - # * m_copy is NULL (claered when the interpreter was destroyed) - # * module's global state was initialized, not reset - - # Use a subinterpreter that sticks around. - loaded_interp1 = self.import_in_subinterp(interpid1) - self.check_common(loaded_interp1) - self.check_semi_fresh(loaded_interp1, loaded_main, base) - - # At this point: - # * alive in 1 interpreter (interp1) - # * module def still in _PyRuntime.imports.extensions - # * mod init func ran again - # * m_copy was copied from interp1 (was NULL) - # * module's global state was updated, not reset - - # Use a subinterpreter while the previous one is still alive. - loaded_interp2 = self.import_in_subinterp(interpid2) - self.check_common(loaded_interp2) - self.check_copied(loaded_interp2, loaded_interp1) - - # At this point: - # * alive in 2 interpreters (interp1, interp2) - # * module def still in _PyRuntime.imports.extensions - # * mod init func ran again - # * m_copy was copied from interp2 (was from interp1) - # * module's global state was updated, not reset - - @requires_subinterpreters - @requires_load_dynamic - def test_basic_multiple_interpreters_reset_each(self): - # resetting between each interpreter - - # At this point: - # * alive in 0 interpreters - # * module def may or may not be loaded already - # * module def not in _PyRuntime.imports.extensions - # * mod init func has not run yet (since reset, at least) - # * m_copy not set (hasn't been loaded yet or already cleared) - # * module's global state has not been initialized yet - # (or already cleared) - - interpid1 = self.add_subinterpreter() - interpid2 = self.add_subinterpreter() - - # Use an interpreter that gets destroyed right away. - loaded = self.import_in_subinterp( - postscript=''' - # Attrs set after loading are not in m_copy. - mod.spam = 'spam, spam, mash, spam, eggs, and spam' - ''', - postcleanup=True, - ) - self.check_common(loaded) - self.check_fresh(loaded) - - # At this point: - # * alive in 0 interpreters - # * module def in _PyRuntime.imports.extensions - # * mod init func ran for the first time (since reset, at least) - # * m_copy is NULL (claered when the interpreter was destroyed) - # * module's global state was initialized, not reset - - # Use a subinterpreter that sticks around. - loaded = self.import_in_subinterp(interpid1, postcleanup=True) - self.check_common(loaded) - self.check_fresh(loaded) - - # At this point: - # * alive in 1 interpreter (interp1) - # * module def still in _PyRuntime.imports.extensions - # * mod init func ran again - # * m_copy was copied from interp1 (was NULL) - # * module's global state was initialized, not reset - - # Use a subinterpreter while the previous one is still alive. - loaded = self.import_in_subinterp(interpid2, postcleanup=True) - self.check_common(loaded) - self.check_fresh(loaded) - - # At this point: - # * alive in 2 interpreters (interp2, interp2) - # * module def still in _PyRuntime.imports.extensions - # * mod init func ran again - # * m_copy was copied from interp2 (was from interp1) - # * module's global state was initialized, not reset - - class ReloadTests(unittest.TestCase): """Very basic tests to make sure that imp.reload() operates just like diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 3ef07203c46c..66ae554f984f 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -2,6 +2,7 @@ import contextlib import errno import glob +import json import importlib.util from importlib._bootstrap_external import _get_sourcefile from importlib.machinery import ( @@ -18,13 +19,15 @@ import textwrap import threading import time +import types import unittest from unittest import mock +import _testinternalcapi from test.support import os_helper from test.support import ( STDLIB_DIR, swap_attr, swap_item, cpython_only, is_emscripten, - is_wasi, run_in_subinterp_with_config) + is_wasi, run_in_subinterp, run_in_subinterp_with_config) from test.support.import_helper import ( forget, make_legacy_pyc, unlink, unload, DirsOnSysPath, CleanImport) from test.support.os_helper import ( @@ -41,6 +44,10 @@ import _testmultiphase except ImportError: _testmultiphase = None +try: + import _xxsubinterpreters as _interpreters +except ModuleNotFoundError: + _interpreters = None skip_if_dont_write_bytecode = unittest.skipIf( @@ -120,6 +127,182 @@ def _ready_to_import(name=None, source=""): del sys.modules[name] +def requires_subinterpreters(meth): + """Decorator to skip a test if subinterpreters are not supported.""" + return unittest.skipIf(_interpreters is None, + 'subinterpreters required')(meth) + + +def requires_singlephase_init(meth): + """Decorator to skip if single-phase init modules are not supported.""" + meth = cpython_only(meth) + return unittest.skipIf(_testsinglephase is None, + 'test requires _testsinglephase module')(meth) + + +class ModuleSnapshot(types.SimpleNamespace): + """A representation of a module for testing. + + Fields: + + * id - the module's object ID + * module - the actual module or an adequate substitute + * __file__ + * __spec__ + * name + * origin + * ns - a copy (dict) of the module's __dict__ (or None) + * ns_id - the object ID of the module's __dict__ + * cached - the sys.modules[mod.__spec__.name] entry (or None) + * cached_id - the object ID of the sys.modules entry (or None) + + In cases where the value is not available (e.g. due to serialization), + the value will be None. + """ + _fields = tuple('id module ns ns_id cached cached_id'.split()) + + @classmethod + def from_module(cls, mod): + name = mod.__spec__.name + cached = sys.modules.get(name) + return cls( + id=id(mod), + module=mod, + ns=types.SimpleNamespace(**mod.__dict__), + ns_id=id(mod.__dict__), + cached=cached, + cached_id=id(cached), + ) + + SCRIPT = textwrap.dedent(''' + {imports} + + name = {name!r} + + {prescript} + + mod = {name} + + {body} + + {postscript} + ''') + IMPORTS = textwrap.dedent(''' + import sys + ''').strip() + SCRIPT_BODY = textwrap.dedent(''' + # Capture the snapshot data. + cached = sys.modules.get(name) + snapshot = dict( + id=id(mod), + module=dict( + __file__=mod.__file__, + __spec__=dict( + name=mod.__spec__.name, + origin=mod.__spec__.origin, + ), + ), + ns=None, + ns_id=id(mod.__dict__), + cached=None, + cached_id=id(cached) if cached else None, + ) + ''').strip() + CLEANUP_SCRIPT = textwrap.dedent(''' + # Clean up the module. + sys.modules.pop(name, None) + ''').strip() + + @classmethod + def build_script(cls, name, *, + prescript=None, + import_first=False, + postscript=None, + postcleanup=False, + ): + if postcleanup is True: + postcleanup = cls.CLEANUP_SCRIPT + elif isinstance(postcleanup, str): + postcleanup = textwrap.dedent(postcleanup).strip() + postcleanup = cls.CLEANUP_SCRIPT + os.linesep + postcleanup + else: + postcleanup = '' + prescript = textwrap.dedent(prescript).strip() if prescript else '' + postscript = textwrap.dedent(postscript).strip() if postscript else '' + + if postcleanup: + if postscript: + postscript = postscript + os.linesep * 2 + postcleanup + else: + postscript = postcleanup + + if import_first: + prescript += textwrap.dedent(f''' + + # Now import the module. + assert name not in sys.modules + import {name}''') + + return cls.SCRIPT.format( + imports=cls.IMPORTS.strip(), + name=name, + prescript=prescript.strip(), + body=cls.SCRIPT_BODY.strip(), + postscript=postscript, + ) + + @classmethod + def parse(cls, text): + raw = json.loads(text) + mod = raw['module'] + mod['__spec__'] = types.SimpleNamespace(**mod['__spec__']) + raw['module'] = types.SimpleNamespace(**mod) + return cls(**raw) + + @classmethod + def from_subinterp(cls, name, interpid=None, *, pipe=None, **script_kwds): + if pipe is not None: + return cls._from_subinterp(name, interpid, pipe, script_kwds) + pipe = os.pipe() + try: + return cls._from_subinterp(name, interpid, pipe, script_kwds) + finally: + r, w = pipe + os.close(r) + os.close(w) + + @classmethod + def _from_subinterp(cls, name, interpid, pipe, script_kwargs): + r, w = pipe + + # Build the script. + postscript = textwrap.dedent(f''' + # Send the result over the pipe. + import json + import os + os.write({w}, json.dumps(snapshot).encode()) + + ''') + _postscript = script_kwargs.get('postscript') + if _postscript: + _postscript = textwrap.dedent(_postscript).lstrip() + postscript += _postscript + script_kwargs['postscript'] = postscript.strip() + script = cls.build_script(name, **script_kwargs) + + # Run the script. + if interpid is None: + ret = run_in_subinterp(script) + if ret != 0: + raise AssertionError(f'{ret} != 0') + else: + _interpreters.run_string(interpid, script) + + # Parse the results. + text = os.read(r, 1000) + return cls.parse(text.decode()) + + class ImportTests(unittest.TestCase): def setUp(self): @@ -1604,7 +1787,7 @@ def test_frozen_compat(self): with self.subTest(f'{module}: strict, not fresh'): self.check_compatible_here(module, strict=True) - @unittest.skipIf(_testsinglephase is None, "test requires _testsinglephase module") + @requires_singlephase_init def test_single_init_extension_compat(self): module = '_testsinglephase' require_extension(module) @@ -1636,7 +1819,7 @@ def test_python_compat(self): with self.subTest(f'{module}: strict, fresh'): self.check_compatible_fresh(module, strict=True) - @unittest.skipIf(_testsinglephase is None, "test requires _testsinglephase module") + @requires_singlephase_init def test_singlephase_check_with_setting_and_override(self): module = '_testsinglephase' require_extension(module) @@ -1672,6 +1855,685 @@ def check_incompatible(setting, override): check_compatible(False, -1) +class TestSinglePhaseSnapshot(ModuleSnapshot): + + @classmethod + def from_module(cls, mod): + self = super().from_module(mod) + self.summed = mod.sum(1, 2) + self.lookedup = mod.look_up_self() + self.lookedup_id = id(self.lookedup) + self.state_initialized = mod.state_initialized() + if hasattr(mod, 'initialized_count'): + self.init_count = mod.initialized_count() + return self + + SCRIPT_BODY = ModuleSnapshot.SCRIPT_BODY + textwrap.dedent(f''' + snapshot['module'].update(dict( + int_const=mod.int_const, + str_const=mod.str_const, + _module_initialized=mod._module_initialized, + )) + snapshot.update(dict( + summed=mod.sum(1, 2), + lookedup_id=id(mod.look_up_self()), + state_initialized=mod.state_initialized(), + init_count=mod.initialized_count(), + has_spam=hasattr(mod, 'spam'), + spam=getattr(mod, 'spam', None), + )) + ''').rstrip() + + @classmethod + def parse(cls, text): + self = super().parse(text) + if not self.has_spam: + del self.spam + del self.has_spam + return self + + + at requires_singlephase_init +class SinglephaseInitTests(unittest.TestCase): + + NAME = '_testsinglephase' + + @classmethod + def setUpClass(cls): + if '-R' in sys.argv or '--huntrleaks' in sys.argv: + # https://github.com/python/cpython/issues/102251 + raise unittest.SkipTest('unresolved refleaks (see gh-102251)') + + spec = importlib.util.find_spec(cls.NAME) + from importlib.machinery import ExtensionFileLoader + cls.FILE = spec.origin + cls.LOADER = type(spec.loader) + assert cls.LOADER is ExtensionFileLoader + + # Start fresh. + cls.clean_up() + + def tearDown(self): + # Clean up the module. + self.clean_up() + + @classmethod + def clean_up(cls): + name = cls.NAME + filename = cls.FILE + if name in sys.modules: + if hasattr(sys.modules[name], '_clear_globals'): + assert sys.modules[name].__file__ == filename + sys.modules[name]._clear_globals() + del sys.modules[name] + # Clear all internally cached data for the extension. + _testinternalcapi.clear_extension(name, filename) + + ######################### + # helpers + + def add_module_cleanup(self, name): + def clean_up(): + # Clear all internally cached data for the extension. + _testinternalcapi.clear_extension(name, self.FILE) + self.addCleanup(clean_up) + + def _load_dynamic(self, name, path): + """ + Load an extension module. + """ + # This is essentially copied from the old imp module. + from importlib._bootstrap import _load + loader = self.LOADER(name, path) + + # Issue bpo-24748: Skip the sys.modules check in _load_module_shim; + # always load new extension. + spec = importlib.util.spec_from_file_location(name, path, + loader=loader) + return _load(spec) + + def load(self, name): + try: + already_loaded = self.already_loaded + except AttributeError: + already_loaded = self.already_loaded = {} + assert name not in already_loaded + mod = self._load_dynamic(name, self.FILE) + self.assertNotIn(mod, already_loaded.values()) + already_loaded[name] = mod + return types.SimpleNamespace( + name=name, + module=mod, + snapshot=TestSinglePhaseSnapshot.from_module(mod), + ) + + def re_load(self, name, mod): + assert sys.modules[name] is mod + assert mod.__dict__ == mod.__dict__ + reloaded = self._load_dynamic(name, self.FILE) + return types.SimpleNamespace( + name=name, + module=reloaded, + snapshot=TestSinglePhaseSnapshot.from_module(reloaded), + ) + + # subinterpreters + + def add_subinterpreter(self): + interpid = _interpreters.create(isolated=False) + _interpreters.run_string(interpid, textwrap.dedent(''' + import sys + import _testinternalcapi + ''')) + def clean_up(): + _interpreters.run_string(interpid, textwrap.dedent(f''' + name = {self.NAME!r} + if name in sys.modules: + sys.modules[name]._clear_globals() + _testinternalcapi.clear_extension(name, {self.FILE!r}) + ''')) + _interpreters.destroy(interpid) + self.addCleanup(clean_up) + return interpid + + def import_in_subinterp(self, interpid=None, *, + postscript=None, + postcleanup=False, + ): + name = self.NAME + + if postcleanup: + import_ = 'import _testinternalcapi' if interpid is None else '' + postcleanup = f''' + {import_} + mod._clear_globals() + _testinternalcapi.clear_extension(name, {self.FILE!r}) + ''' + + try: + pipe = self._pipe + except AttributeError: + r, w = pipe = self._pipe = os.pipe() + self.addCleanup(os.close, r) + self.addCleanup(os.close, w) + + snapshot = TestSinglePhaseSnapshot.from_subinterp( + name, + interpid, + pipe=pipe, + import_first=True, + postscript=postscript, + postcleanup=postcleanup, + ) + + return types.SimpleNamespace( + name=name, + module=None, + snapshot=snapshot, + ) + + # checks + + def check_common(self, loaded): + isolated = False + + mod = loaded.module + if not mod: + # It came from a subinterpreter. + isolated = True + mod = loaded.snapshot.module + # mod.__name__ might not match, but the spec will. + self.assertEqual(mod.__spec__.name, loaded.name) + self.assertEqual(mod.__file__, self.FILE) + self.assertEqual(mod.__spec__.origin, self.FILE) + if not isolated: + self.assertTrue(issubclass(mod.error, Exception)) + self.assertEqual(mod.int_const, 1969) + self.assertEqual(mod.str_const, 'something different') + self.assertIsInstance(mod._module_initialized, float) + self.assertGreater(mod._module_initialized, 0) + + snap = loaded.snapshot + self.assertEqual(snap.summed, 3) + if snap.state_initialized is not None: + self.assertIsInstance(snap.state_initialized, float) + self.assertGreater(snap.state_initialized, 0) + if isolated: + # The "looked up" module is interpreter-specific + # (interp->imports.modules_by_index was set for the module). + self.assertEqual(snap.lookedup_id, snap.id) + self.assertEqual(snap.cached_id, snap.id) + with self.assertRaises(AttributeError): + snap.spam + else: + self.assertIs(snap.lookedup, mod) + self.assertIs(snap.cached, mod) + + def check_direct(self, loaded): + # The module has its own PyModuleDef, with a matching name. + self.assertEqual(loaded.module.__name__, loaded.name) + self.assertIs(loaded.snapshot.lookedup, loaded.module) + + def check_indirect(self, loaded, orig): + # The module re-uses another's PyModuleDef, with a different name. + assert orig is not loaded.module + assert orig.__name__ != loaded.name + self.assertNotEqual(loaded.module.__name__, loaded.name) + self.assertIs(loaded.snapshot.lookedup, loaded.module) + + def check_basic(self, loaded, expected_init_count): + # m_size == -1 + # The module loads fresh the first time and copies m_copy after. + snap = loaded.snapshot + self.assertIsNot(snap.state_initialized, None) + self.assertIsInstance(snap.init_count, int) + self.assertGreater(snap.init_count, 0) + self.assertEqual(snap.init_count, expected_init_count) + + def check_with_reinit(self, loaded): + # m_size >= 0 + # The module loads fresh every time. + pass + + def check_fresh(self, loaded): + """ + The module had not been loaded before (at least since fully reset). + """ + snap = loaded.snapshot + # The module's init func was run. + # A copy of the module's __dict__ was stored in def->m_base.m_copy. + # The previous m_copy was deleted first. + # _PyRuntime.imports.extensions was set. + self.assertEqual(snap.init_count, 1) + # The global state was initialized. + # The module attrs were initialized from that state. + self.assertEqual(snap.module._module_initialized, + snap.state_initialized) + + def check_semi_fresh(self, loaded, base, prev): + """ + The module had been loaded before and then reset + (but the module global state wasn't). + """ + snap = loaded.snapshot + # The module's init func was run again. + # A copy of the module's __dict__ was stored in def->m_base.m_copy. + # The previous m_copy was deleted first. + # The module globals did not get reset. + self.assertNotEqual(snap.id, base.snapshot.id) + self.assertNotEqual(snap.id, prev.snapshot.id) + self.assertEqual(snap.init_count, prev.snapshot.init_count + 1) + # The global state was updated. + # The module attrs were initialized from that state. + self.assertEqual(snap.module._module_initialized, + snap.state_initialized) + self.assertNotEqual(snap.state_initialized, + base.snapshot.state_initialized) + self.assertNotEqual(snap.state_initialized, + prev.snapshot.state_initialized) + + def check_copied(self, loaded, base): + """ + The module had been loaded before and never reset. + """ + snap = loaded.snapshot + # The module's init func was not run again. + # The interpreter copied m_copy, as set by the other interpreter, + # with objects owned by the other interpreter. + # The module globals did not get reset. + self.assertNotEqual(snap.id, base.snapshot.id) + self.assertEqual(snap.init_count, base.snapshot.init_count) + # The global state was not updated since the init func did not run. + # The module attrs were not directly initialized from that state. + # The state and module attrs still match the previous loading. + self.assertEqual(snap.module._module_initialized, + snap.state_initialized) + self.assertEqual(snap.state_initialized, + base.snapshot.state_initialized) + + ######################### + # the tests + + def test_cleared_globals(self): + loaded = self.load(self.NAME) + _testsinglephase = loaded.module + init_before = _testsinglephase.state_initialized() + + _testsinglephase._clear_globals() + init_after = _testsinglephase.state_initialized() + init_count = _testsinglephase.initialized_count() + + self.assertGreater(init_before, 0) + self.assertEqual(init_after, 0) + self.assertEqual(init_count, -1) + + def test_variants(self): + # Exercise the most meaningful variants described in Python/import.c. + self.maxDiff = None + + # Check the "basic" module. + + name = self.NAME + expected_init_count = 1 + with self.subTest(name): + loaded = self.load(name) + + self.check_common(loaded) + self.check_direct(loaded) + self.check_basic(loaded, expected_init_count) + basic = loaded.module + + # Check its indirect variants. + + name = f'{self.NAME}_basic_wrapper' + self.add_module_cleanup(name) + expected_init_count += 1 + with self.subTest(name): + loaded = self.load(name) + + self.check_common(loaded) + self.check_indirect(loaded, basic) + self.check_basic(loaded, expected_init_count) + + # Currently PyState_AddModule() always replaces the cached module. + self.assertIs(basic.look_up_self(), loaded.module) + self.assertEqual(basic.initialized_count(), expected_init_count) + + # The cached module shouldn't change after this point. + basic_lookedup = loaded.module + + # Check its direct variant. + + name = f'{self.NAME}_basic_copy' + self.add_module_cleanup(name) + expected_init_count += 1 + with self.subTest(name): + loaded = self.load(name) + + self.check_common(loaded) + self.check_direct(loaded) + self.check_basic(loaded, expected_init_count) + + # This should change the cached module for _testsinglephase. + self.assertIs(basic.look_up_self(), basic_lookedup) + self.assertEqual(basic.initialized_count(), expected_init_count) + + # Check the non-basic variant that has no state. + + name = f'{self.NAME}_with_reinit' + self.add_module_cleanup(name) + with self.subTest(name): + loaded = self.load(name) + + self.check_common(loaded) + self.assertIs(loaded.snapshot.state_initialized, None) + self.check_direct(loaded) + self.check_with_reinit(loaded) + + # This should change the cached module for _testsinglephase. + self.assertIs(basic.look_up_self(), basic_lookedup) + self.assertEqual(basic.initialized_count(), expected_init_count) + + # Check the basic variant that has state. + + name = f'{self.NAME}_with_state' + self.add_module_cleanup(name) + with self.subTest(name): + loaded = self.load(name) + + self.check_common(loaded) + self.assertIsNot(loaded.snapshot.state_initialized, None) + self.check_direct(loaded) + self.check_with_reinit(loaded) + + # This should change the cached module for _testsinglephase. + self.assertIs(basic.look_up_self(), basic_lookedup) + self.assertEqual(basic.initialized_count(), expected_init_count) + + def test_basic_reloaded(self): + # m_copy is copied into the existing module object. + # Global state is not changed. + self.maxDiff = None + + for name in [ + self.NAME, # the "basic" module + f'{self.NAME}_basic_wrapper', # the indirect variant + f'{self.NAME}_basic_copy', # the direct variant + ]: + self.add_module_cleanup(name) + with self.subTest(name): + loaded = self.load(name) + reloaded = self.re_load(name, loaded.module) + + self.check_common(loaded) + self.check_common(reloaded) + + # Make sure the original __dict__ did not get replaced. + self.assertEqual(id(loaded.module.__dict__), + loaded.snapshot.ns_id) + self.assertEqual(loaded.snapshot.ns.__dict__, + loaded.module.__dict__) + + self.assertEqual(reloaded.module.__spec__.name, reloaded.name) + self.assertEqual(reloaded.module.__name__, + reloaded.snapshot.ns.__name__) + + self.assertIs(reloaded.module, loaded.module) + self.assertIs(reloaded.module.__dict__, loaded.module.__dict__) + # It only happens to be the same but that's good enough here. + # We really just want to verify that the re-loaded attrs + # didn't change. + self.assertIs(reloaded.snapshot.lookedup, + loaded.snapshot.lookedup) + self.assertEqual(reloaded.snapshot.state_initialized, + loaded.snapshot.state_initialized) + self.assertEqual(reloaded.snapshot.init_count, + loaded.snapshot.init_count) + + self.assertIs(reloaded.snapshot.cached, reloaded.module) + + def test_with_reinit_reloaded(self): + # The module's m_init func is run again. + self.maxDiff = None + + # Keep a reference around. + basic = self.load(self.NAME) + + for name in [ + f'{self.NAME}_with_reinit', # m_size == 0 + f'{self.NAME}_with_state', # m_size > 0 + ]: + self.add_module_cleanup(name) + with self.subTest(name): + loaded = self.load(name) + reloaded = self.re_load(name, loaded.module) + + self.check_common(loaded) + self.check_common(reloaded) + + # Make sure the original __dict__ did not get replaced. + self.assertEqual(id(loaded.module.__dict__), + loaded.snapshot.ns_id) + self.assertEqual(loaded.snapshot.ns.__dict__, + loaded.module.__dict__) + + self.assertEqual(reloaded.module.__spec__.name, reloaded.name) + self.assertEqual(reloaded.module.__name__, + reloaded.snapshot.ns.__name__) + + self.assertIsNot(reloaded.module, loaded.module) + self.assertNotEqual(reloaded.module.__dict__, + loaded.module.__dict__) + self.assertIs(reloaded.snapshot.lookedup, reloaded.module) + if loaded.snapshot.state_initialized is None: + self.assertIs(reloaded.snapshot.state_initialized, None) + else: + self.assertGreater(reloaded.snapshot.state_initialized, + loaded.snapshot.state_initialized) + + self.assertIs(reloaded.snapshot.cached, reloaded.module) + + # Currently, for every single-phrase init module loaded + # in multiple interpreters, those interpreters share a + # PyModuleDef for that object, which can be a problem. + # Also, we test with a single-phase module that has global state, + # which is shared by all interpreters. + + @requires_subinterpreters + def test_basic_multiple_interpreters_main_no_reset(self): + # without resetting; already loaded in main interpreter + + # At this point: + # * alive in 0 interpreters + # * module def may or may not be loaded already + # * module def not in _PyRuntime.imports.extensions + # * mod init func has not run yet (since reset, at least) + # * m_copy not set (hasn't been loaded yet or already cleared) + # * module's global state has not been initialized yet + # (or already cleared) + + main_loaded = self.load(self.NAME) + _testsinglephase = main_loaded.module + # Attrs set after loading are not in m_copy. + _testsinglephase.spam = 'spam, spam, spam, spam, eggs, and spam' + + self.check_common(main_loaded) + self.check_fresh(main_loaded) + + interpid1 = self.add_subinterpreter() + interpid2 = self.add_subinterpreter() + + # At this point: + # * alive in 1 interpreter (main) + # * module def in _PyRuntime.imports.extensions + # * mod init func ran for the first time (since reset, at least) + # * m_copy was copied from the main interpreter (was NULL) + # * module's global state was initialized + + # Use an interpreter that gets destroyed right away. + loaded = self.import_in_subinterp() + self.check_common(loaded) + self.check_copied(loaded, main_loaded) + + # At this point: + # * alive in 1 interpreter (main) + # * module def still in _PyRuntime.imports.extensions + # * mod init func ran again + # * m_copy is NULL (claered when the interpreter was destroyed) + # (was from main interpreter) + # * module's global state was updated, not reset + + # Use a subinterpreter that sticks around. + loaded = self.import_in_subinterp(interpid1) + self.check_common(loaded) + self.check_copied(loaded, main_loaded) + + # At this point: + # * alive in 2 interpreters (main, interp1) + # * module def still in _PyRuntime.imports.extensions + # * mod init func ran again + # * m_copy was copied from interp1 + # * module's global state was updated, not reset + + # Use a subinterpreter while the previous one is still alive. + loaded = self.import_in_subinterp(interpid2) + self.check_common(loaded) + self.check_copied(loaded, main_loaded) + + # At this point: + # * alive in 3 interpreters (main, interp1, interp2) + # * module def still in _PyRuntime.imports.extensions + # * mod init func ran again + # * m_copy was copied from interp2 (was from interp1) + # * module's global state was updated, not reset + + @requires_subinterpreters + def test_basic_multiple_interpreters_deleted_no_reset(self): + # without resetting; already loaded in a deleted interpreter + + # At this point: + # * alive in 0 interpreters + # * module def may or may not be loaded already + # * module def not in _PyRuntime.imports.extensions + # * mod init func has not run yet (since reset, at least) + # * m_copy not set (hasn't been loaded yet or already cleared) + # * module's global state has not been initialized yet + # (or already cleared) + + interpid1 = self.add_subinterpreter() + interpid2 = self.add_subinterpreter() + + # First, load in the main interpreter but then completely clear it. + loaded_main = self.load(self.NAME) + loaded_main.module._clear_globals() + _testinternalcapi.clear_extension(self.NAME, self.FILE) + + # At this point: + # * alive in 0 interpreters + # * module def loaded already + # * module def was in _PyRuntime.imports.extensions, but cleared + # * mod init func ran for the first time (since reset, at least) + # * m_copy was set, but cleared (was NULL) + # * module's global state was initialized but cleared + + # Start with an interpreter that gets destroyed right away. + base = self.import_in_subinterp(postscript=''' + # Attrs set after loading are not in m_copy. + mod.spam = 'spam, spam, mash, spam, eggs, and spam' + ''') + self.check_common(base) + self.check_fresh(base) + + # At this point: + # * alive in 0 interpreters + # * module def in _PyRuntime.imports.extensions + # * mod init func ran again + # * m_copy is NULL (claered when the interpreter was destroyed) + # * module's global state was initialized, not reset + + # Use a subinterpreter that sticks around. + loaded_interp1 = self.import_in_subinterp(interpid1) + self.check_common(loaded_interp1) + self.check_semi_fresh(loaded_interp1, loaded_main, base) + + # At this point: + # * alive in 1 interpreter (interp1) + # * module def still in _PyRuntime.imports.extensions + # * mod init func ran again + # * m_copy was copied from interp1 (was NULL) + # * module's global state was updated, not reset + + # Use a subinterpreter while the previous one is still alive. + loaded_interp2 = self.import_in_subinterp(interpid2) + self.check_common(loaded_interp2) + self.check_copied(loaded_interp2, loaded_interp1) + + # At this point: + # * alive in 2 interpreters (interp1, interp2) + # * module def still in _PyRuntime.imports.extensions + # * mod init func ran again + # * m_copy was copied from interp2 (was from interp1) + # * module's global state was updated, not reset + + @requires_subinterpreters + def test_basic_multiple_interpreters_reset_each(self): + # resetting between each interpreter + + # At this point: + # * alive in 0 interpreters + # * module def may or may not be loaded already + # * module def not in _PyRuntime.imports.extensions + # * mod init func has not run yet (since reset, at least) + # * m_copy not set (hasn't been loaded yet or already cleared) + # * module's global state has not been initialized yet + # (or already cleared) + + interpid1 = self.add_subinterpreter() + interpid2 = self.add_subinterpreter() + + # Use an interpreter that gets destroyed right away. + loaded = self.import_in_subinterp( + postscript=''' + # Attrs set after loading are not in m_copy. + mod.spam = 'spam, spam, mash, spam, eggs, and spam' + ''', + postcleanup=True, + ) + self.check_common(loaded) + self.check_fresh(loaded) + + # At this point: + # * alive in 0 interpreters + # * module def in _PyRuntime.imports.extensions + # * mod init func ran for the first time (since reset, at least) + # * m_copy is NULL (claered when the interpreter was destroyed) + # * module's global state was initialized, not reset + + # Use a subinterpreter that sticks around. + loaded = self.import_in_subinterp(interpid1, postcleanup=True) + self.check_common(loaded) + self.check_fresh(loaded) + + # At this point: + # * alive in 1 interpreter (interp1) + # * module def still in _PyRuntime.imports.extensions + # * mod init func ran again + # * m_copy was copied from interp1 (was NULL) + # * module's global state was initialized, not reset + + # Use a subinterpreter while the previous one is still alive. + loaded = self.import_in_subinterp(interpid2, postcleanup=True) + self.check_common(loaded) + self.check_fresh(loaded) + + # At this point: + # * alive in 2 interpreters (interp2, interp2) + # * module def still in _PyRuntime.imports.extensions + # * mod init func ran again + # * m_copy was copied from interp2 (was from interp1) + # * module's global state was initialized, not reset + + if __name__ == '__main__': # Test needs to be a package, so we can do relative imports. unittest.main() From webhook-mailer at python.org Thu Apr 20 10:08:11 2023 From: webhook-mailer at python.org (gvanrossum) Date: Thu, 20 Apr 2023 14:08:11 -0000 Subject: [Python-checkins] gh-98641: Document difference between task group and gather (#103644) Message-ID: https://github.com/python/cpython/commit/4898415df724380d4c8b0ec08e8cb92f126193c3 commit: 4898415df724380d4c8b0ec08e8cb92f126193c3 branch: main author: Adrien committer: gvanrossum date: 2023-04-20T07:07:41-07:00 summary: gh-98641: Document difference between task group and gather (#103644) The purpose of the comments is to rule out the implication that asyncio.TaskGroup is a drop-in replacement / better alternative to asyncio.gather(). files: M Doc/library/asyncio-task.rst diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index b81d89acf7fd..ba0f909c405a 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -256,8 +256,9 @@ Creating Tasks .. note:: - :meth:`asyncio.TaskGroup.create_task` is a newer alternative - that allows for convenient waiting for a group of related tasks. + :meth:`asyncio.TaskGroup.create_task` is a new alternative + leveraging structural concurrency; it allows for waiting + for a group of related tasks with strong safety guarantees. .. important:: @@ -340,7 +341,7 @@ Example:: async with asyncio.TaskGroup() as tg: task1 = tg.create_task(some_coro(...)) task2 = tg.create_task(another_coro(...)) - print("Both tasks have completed now.") + print(f"Both tasks have completed now: {task1.result()}, {task2.result()}") The ``async with`` statement will wait for all tasks in the group to finish. While waiting, new tasks may still be added to the group @@ -459,8 +460,12 @@ Running Tasks Concurrently Tasks/Futures to be cancelled. .. note:: - A more modern way to create and run tasks concurrently and - wait for their completion is :class:`asyncio.TaskGroup`. + A new alternative to create and run tasks concurrently and + wait for their completion is :class:`asyncio.TaskGroup`. *TaskGroup* + provides stronger safety guarantees than *gather* for scheduling a nesting of subtasks: + if a task (or a subtask, a task scheduled by a task) + raises an exception, *TaskGroup* will, while *gather* will not, + cancel the remaining scheduled tasks). .. _asyncio_example_gather: From webhook-mailer at python.org Thu Apr 20 22:04:37 2023 From: webhook-mailer at python.org (orsenthil) Date: Fri, 21 Apr 2023 02:04:37 -0000 Subject: [Python-checkins] gh-99352: Respect `http.client.HTTPConnection.debuglevel` in `urllib.request.AbstractHTTPHandler` (#99353) Message-ID: https://github.com/python/cpython/commit/5c00a6224d55f8818ef567b93f484b5429e2ae80 commit: 5c00a6224d55f8818ef567b93f484b5429e2ae80 branch: main author: Wheeler Law committer: orsenthil date: 2023-04-20T19:04:25-07:00 summary: gh-99352: Respect `http.client.HTTPConnection.debuglevel` in `urllib.request.AbstractHTTPHandler` (#99353) * bugfix: let the HTTP- and HTTPSHandlers respect the value of http.client.HTTPConnection.debuglevel * add tests * add news * ReSTify NEWS and reword a bit. * Address Review Comments. * Use mock.patch.object instead of settting the module level value. * Used test values to assert the debuglevel. --------- Co-authored-by: Gregory P. Smith Co-authored-by: Senthil Kumaran files: A Misc/NEWS.d/next/Library/2022-11-10-16-26-47.gh-issue-99353.DQFjnt.rst M Lib/test/test_urllib2.py M Lib/urllib/request.py diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py index 633d596ac3de..b7c6f6dd8f1b 100644 --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -3,6 +3,7 @@ from test.support import os_helper from test.support import warnings_helper from test import test_urllib +from unittest import mock import os import io @@ -484,7 +485,18 @@ def build_test_opener(*handler_instances): return opener -class MockHTTPHandler(urllib.request.BaseHandler): +class MockHTTPHandler(urllib.request.HTTPHandler): + # Very simple mock HTTP handler with no special behavior other than using a mock HTTP connection + + def __init__(self, debuglevel=None): + super(MockHTTPHandler, self).__init__(debuglevel=debuglevel) + self.httpconn = MockHTTPClass() + + def http_open(self, req): + return self.do_open(self.httpconn, req) + + +class MockHTTPHandlerRedirect(urllib.request.BaseHandler): # useful for testing redirections and auth # sends supplied headers and code as first response # sends 200 OK as second response @@ -512,12 +524,12 @@ def http_open(self, req): return MockResponse(200, "OK", msg, "", req.get_full_url()) -class MockHTTPSHandler(urllib.request.AbstractHTTPHandler): +class MockHTTPSHandler(urllib.request.HTTPSHandler): # Useful for testing the Proxy-Authorization request by verifying the # properties of httpcon - def __init__(self, debuglevel=0): - urllib.request.AbstractHTTPHandler.__init__(self, debuglevel=debuglevel) + def __init__(self, debuglevel=None, context=None, check_hostname=None): + super(MockHTTPSHandler, self).__init__(debuglevel, context, check_hostname) self.httpconn = MockHTTPClass() def https_open(self, req): @@ -1048,12 +1060,35 @@ def test_http_body_array(self): newreq = h.do_request_(req) self.assertEqual(int(newreq.get_header('Content-length')),16) - def test_http_handler_debuglevel(self): + def test_http_handler_global_debuglevel(self): + with mock.patch.object(http.client.HTTPConnection, 'debuglevel', 6): + o = OpenerDirector() + h = MockHTTPHandler() + o.add_handler(h) + o.open("http://www.example.com") + self.assertEqual(h._debuglevel, 6) + + def test_http_handler_local_debuglevel(self): + o = OpenerDirector() + h = MockHTTPHandler(debuglevel=5) + o.add_handler(h) + o.open("http://www.example.com") + self.assertEqual(h._debuglevel, 5) + + def test_https_handler_global_debuglevel(self): + with mock.patch.object(http.client.HTTPSConnection, 'debuglevel', 7): + o = OpenerDirector() + h = MockHTTPSHandler() + o.add_handler(h) + o.open("https://www.example.com") + self.assertEqual(h._debuglevel, 7) + + def test_https_handler_local_debuglevel(self): o = OpenerDirector() - h = MockHTTPSHandler(debuglevel=1) + h = MockHTTPSHandler(debuglevel=4) o.add_handler(h) o.open("https://www.example.com") - self.assertEqual(h._debuglevel, 1) + self.assertEqual(h._debuglevel, 4) def test_http_doubleslash(self): # Checks the presence of any unnecessary double slash in url does not @@ -1289,7 +1324,7 @@ def test_cookie_redirect(self): cj = CookieJar() interact_netscape(cj, "http://www.example.com/", "spam=eggs") - hh = MockHTTPHandler(302, "Location: http://www.cracker.com/\r\n\r\n") + hh = MockHTTPHandlerRedirect(302, "Location: http://www.cracker.com/\r\n\r\n") hdeh = urllib.request.HTTPDefaultErrorHandler() hrh = urllib.request.HTTPRedirectHandler() cp = urllib.request.HTTPCookieProcessor(cj) @@ -1299,7 +1334,7 @@ def test_cookie_redirect(self): def test_redirect_fragment(self): redirected_url = 'http://www.example.com/index.html#OK\r\n\r\n' - hh = MockHTTPHandler(302, 'Location: ' + redirected_url) + hh = MockHTTPHandlerRedirect(302, 'Location: ' + redirected_url) hdeh = urllib.request.HTTPDefaultErrorHandler() hrh = urllib.request.HTTPRedirectHandler() o = build_test_opener(hh, hdeh, hrh) @@ -1484,7 +1519,7 @@ def check_basic_auth(self, headers, realm): password_manager = MockPasswordManager() auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager) body = '\r\n'.join(headers) + '\r\n\r\n' - http_handler = MockHTTPHandler(401, body) + http_handler = MockHTTPHandlerRedirect(401, body) opener.add_handler(auth_handler) opener.add_handler(http_handler) self._test_basic_auth(opener, auth_handler, "Authorization", @@ -1544,7 +1579,7 @@ def test_proxy_basic_auth(self): password_manager = MockPasswordManager() auth_handler = urllib.request.ProxyBasicAuthHandler(password_manager) realm = "ACME Networks" - http_handler = MockHTTPHandler( + http_handler = MockHTTPHandlerRedirect( 407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm) opener.add_handler(auth_handler) opener.add_handler(http_handler) @@ -1588,7 +1623,7 @@ def http_error_401(self, *args, **kwds): digest_handler = TestDigestAuthHandler(password_manager) basic_handler = TestBasicAuthHandler(password_manager) realm = "ACME Networks" - http_handler = MockHTTPHandler( + http_handler = MockHTTPHandlerRedirect( 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm) opener.add_handler(basic_handler) opener.add_handler(digest_handler) @@ -1608,7 +1643,7 @@ def test_unsupported_auth_digest_handler(self): opener = OpenerDirector() # While using DigestAuthHandler digest_auth_handler = urllib.request.HTTPDigestAuthHandler(None) - http_handler = MockHTTPHandler( + http_handler = MockHTTPHandlerRedirect( 401, 'WWW-Authenticate: Kerberos\r\n\r\n') opener.add_handler(digest_auth_handler) opener.add_handler(http_handler) @@ -1618,7 +1653,7 @@ def test_unsupported_auth_basic_handler(self): # While using BasicAuthHandler opener = OpenerDirector() basic_auth_handler = urllib.request.HTTPBasicAuthHandler(None) - http_handler = MockHTTPHandler( + http_handler = MockHTTPHandlerRedirect( 401, 'WWW-Authenticate: NTLM\r\n\r\n') opener.add_handler(basic_auth_handler) opener.add_handler(http_handler) @@ -1705,7 +1740,7 @@ def test_basic_prior_auth_send_after_first_success(self): opener = OpenerDirector() opener.add_handler(auth_prior_handler) - http_handler = MockHTTPHandler( + http_handler = MockHTTPHandlerRedirect( 401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % None) opener.add_handler(http_handler) diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index 151034e6a81b..19e2e5bd3356 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -1251,8 +1251,8 @@ def http_error_407(self, req, fp, code, msg, headers): class AbstractHTTPHandler(BaseHandler): - def __init__(self, debuglevel=0): - self._debuglevel = debuglevel + def __init__(self, debuglevel=None): + self._debuglevel = debuglevel if debuglevel is not None else http.client.HTTPConnection.debuglevel def set_http_debuglevel(self, level): self._debuglevel = level @@ -1378,7 +1378,8 @@ def http_open(self, req): class HTTPSHandler(AbstractHTTPHandler): - def __init__(self, debuglevel=0, context=None, check_hostname=None): + def __init__(self, debuglevel=None, context=None, check_hostname=None): + debuglevel = debuglevel if debuglevel is not None else http.client.HTTPSConnection.debuglevel AbstractHTTPHandler.__init__(self, debuglevel) if context is None: http_version = http.client.HTTPSConnection._http_vsn diff --git a/Misc/NEWS.d/next/Library/2022-11-10-16-26-47.gh-issue-99353.DQFjnt.rst b/Misc/NEWS.d/next/Library/2022-11-10-16-26-47.gh-issue-99353.DQFjnt.rst new file mode 100644 index 000000000000..1ad42d5c9aa5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-11-10-16-26-47.gh-issue-99353.DQFjnt.rst @@ -0,0 +1,3 @@ +Respect the :class:`http.client.HTTPConnection` ``.debuglevel`` flag +in :class:`urllib.request.AbstractHTTPHandler` when its constructor +parameter ``debuglevel`` is not set. And do the same for ``*HTTPS*``. From webhook-mailer at python.org Thu Apr 20 22:12:55 2023 From: webhook-mailer at python.org (jaraco) Date: Fri, 21 Apr 2023 02:12:55 -0000 Subject: [Python-checkins] Sync with importlib_metadata 6.5 (GH-103584) Message-ID: https://github.com/python/cpython/commit/3e0fec7e07a71bdeeab7554e980110fbc47763b9 commit: 3e0fec7e07a71bdeeab7554e980110fbc47763b9 branch: main author: Jason R. Coombs committer: jaraco date: 2023-04-20T22:12:48-04:00 summary: Sync with importlib_metadata 6.5 (GH-103584) files: A Lib/test/test_importlib/_context.py A Lib/test/test_importlib/_path.py A Misc/NEWS.d/next/Library/2023-04-16-19-48-21.gh-issue-103584.3mBTuM.rst M Doc/library/importlib.metadata.rst M Lib/importlib/metadata/__init__.py M Lib/importlib/metadata/_adapters.py M Lib/importlib/metadata/_meta.py M Lib/test/test_importlib/fixtures.py M Lib/test/test_importlib/test_main.py M Lib/test/test_importlib/test_metadata_api.py diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst index 6e084101995e..b306d5f55a71 100644 --- a/Doc/library/importlib.metadata.rst +++ b/Doc/library/importlib.metadata.rst @@ -308,6 +308,10 @@ Python module or `Import Package >> packages_distributions() {'importlib_metadata': ['importlib-metadata'], 'yaml': ['PyYAML'], 'jaraco': ['jaraco.classes', 'jaraco.functools'], ...} +Some editable installs, `do not supply top-level names +`_, and thus this +function is not reliable with such installs. + .. versionadded:: 3.10 .. _distributions: diff --git a/Lib/importlib/metadata/__init__.py b/Lib/importlib/metadata/__init__.py index 40ab1a1aaac3..b8eb19d05dcc 100644 --- a/Lib/importlib/metadata/__init__.py +++ b/Lib/importlib/metadata/__init__.py @@ -12,7 +12,9 @@ import functools import itertools import posixpath +import contextlib import collections +import inspect from . import _adapters, _meta from ._collections import FreezableDefaultDict, Pair @@ -24,7 +26,7 @@ from importlib import import_module from importlib.abc import MetaPathFinder from itertools import starmap -from typing import List, Mapping, Optional +from typing import List, Mapping, Optional, cast __all__ = [ @@ -341,11 +343,30 @@ def __repr__(self): return f'' -class Distribution: +class DeprecatedNonAbstract: + def __new__(cls, *args, **kwargs): + all_names = { + name for subclass in inspect.getmro(cls) for name in vars(subclass) + } + abstract = { + name + for name in all_names + if getattr(getattr(cls, name), '__isabstractmethod__', False) + } + if abstract: + warnings.warn( + f"Unimplemented abstract methods {abstract}", + DeprecationWarning, + stacklevel=2, + ) + return super().__new__(cls) + + +class Distribution(DeprecatedNonAbstract): """A Python distribution package.""" @abc.abstractmethod - def read_text(self, filename): + def read_text(self, filename) -> Optional[str]: """Attempt to load metadata file given by the name. :param filename: The name of the file in the distribution info. @@ -419,7 +440,7 @@ def metadata(self) -> _meta.PackageMetadata: The returned object will have keys that name the various bits of metadata. See PEP 566 for details. """ - text = ( + opt_text = ( self.read_text('METADATA') or self.read_text('PKG-INFO') # This last clause is here to support old egg-info files. Its @@ -427,6 +448,7 @@ def metadata(self) -> _meta.PackageMetadata: # (which points to the egg-info file) attribute unchanged. or self.read_text('') ) + text = cast(str, opt_text) return _adapters.Message(email.message_from_string(text)) @property @@ -455,8 +477,8 @@ def files(self): :return: List of PackagePath for this distribution or None Result is `None` if the metadata file that enumerates files - (i.e. RECORD for dist-info or SOURCES.txt for egg-info) is - missing. + (i.e. RECORD for dist-info, or installed-files.txt or + SOURCES.txt for egg-info) is missing. Result may be empty if the metadata exists but is empty. """ @@ -469,9 +491,19 @@ def make_file(name, hash=None, size_str=None): @pass_none def make_files(lines): - return list(starmap(make_file, csv.reader(lines))) + return starmap(make_file, csv.reader(lines)) - return make_files(self._read_files_distinfo() or self._read_files_egginfo()) + @pass_none + def skip_missing_files(package_paths): + return list(filter(lambda path: path.locate().exists(), package_paths)) + + return skip_missing_files( + make_files( + self._read_files_distinfo() + or self._read_files_egginfo_installed() + or self._read_files_egginfo_sources() + ) + ) def _read_files_distinfo(self): """ @@ -480,10 +512,43 @@ def _read_files_distinfo(self): text = self.read_text('RECORD') return text and text.splitlines() - def _read_files_egginfo(self): + def _read_files_egginfo_installed(self): + """ + Read installed-files.txt and return lines in a similar + CSV-parsable format as RECORD: each file must be placed + relative to the site-packages directory, and must also be + quoted (since file names can contain literal commas). + + This file is written when the package is installed by pip, + but it might not be written for other installation methods. + Hence, even if we can assume that this file is accurate + when it exists, we cannot assume that it always exists. """ - SOURCES.txt might contain literal commas, so wrap each line - in quotes. + text = self.read_text('installed-files.txt') + # We need to prepend the .egg-info/ subdir to the lines in this file. + # But this subdir is only available in the PathDistribution's self._path + # which is not easily accessible from this base class... + subdir = getattr(self, '_path', None) + if not text or not subdir: + return + with contextlib.suppress(Exception): + ret = [ + str((subdir / line).resolve().relative_to(self.locate_file(''))) + for line in text.splitlines() + ] + return map('"{}"'.format, ret) + + def _read_files_egginfo_sources(self): + """ + Read SOURCES.txt and return lines in a similar CSV-parsable + format as RECORD: each file name must be quoted (since it + might contain literal commas). + + Note that SOURCES.txt is not a reliable source for what + files are installed by a package. This file is generated + for a source archive, and the files that are present + there (e.g. setup.py) may not correctly reflect the files + that are present after the package has been installed. """ text = self.read_text('SOURCES.txt') return text and map('"{}"'.format, text.splitlines()) @@ -886,8 +951,13 @@ def _top_level_declared(dist): def _top_level_inferred(dist): - return { - f.parts[0] if len(f.parts) > 1 else f.with_suffix('').name + opt_names = { + f.parts[0] if len(f.parts) > 1 else inspect.getmodulename(f) for f in always_iterable(dist.files) - if f.suffix == ".py" } + + @pass_none + def importable_name(name): + return '.' not in name + + return filter(importable_name, opt_names) diff --git a/Lib/importlib/metadata/_adapters.py b/Lib/importlib/metadata/_adapters.py index aa460d3eda50..6aed69a30857 100644 --- a/Lib/importlib/metadata/_adapters.py +++ b/Lib/importlib/metadata/_adapters.py @@ -1,3 +1,5 @@ +import functools +import warnings import re import textwrap import email.message @@ -5,6 +7,15 @@ from ._text import FoldedCase +# Do not remove prior to 2024-01-01 or Python 3.14 +_warn = functools.partial( + warnings.warn, + "Implicit None on return values is deprecated and will raise KeyErrors.", + DeprecationWarning, + stacklevel=2, +) + + class Message(email.message.Message): multiple_use_keys = set( map( @@ -39,6 +50,16 @@ def __init__(self, *args, **kwargs): def __iter__(self): return super().__iter__() + def __getitem__(self, item): + """ + Warn users that a ``KeyError`` can be expected when a + mising key is supplied. Ref python/importlib_metadata#371. + """ + res = super().__getitem__(item) + if res is None: + _warn() + return res + def _repair_headers(self): def redent(value): "Correct for RFC822 indentation" diff --git a/Lib/importlib/metadata/_meta.py b/Lib/importlib/metadata/_meta.py index d5c0576194ec..c9a7ef906a8a 100644 --- a/Lib/importlib/metadata/_meta.py +++ b/Lib/importlib/metadata/_meta.py @@ -1,4 +1,5 @@ -from typing import Any, Dict, Iterator, List, Protocol, TypeVar, Union +from typing import Protocol +from typing import Any, Dict, Iterator, List, Optional, TypeVar, Union, overload _T = TypeVar("_T") @@ -17,7 +18,21 @@ def __getitem__(self, key: str) -> str: def __iter__(self) -> Iterator[str]: ... # pragma: no cover - def get_all(self, name: str, failobj: _T = ...) -> Union[List[Any], _T]: + @overload + def get(self, name: str, failobj: None = None) -> Optional[str]: + ... # pragma: no cover + + @overload + def get(self, name: str, failobj: _T) -> Union[str, _T]: + ... # pragma: no cover + + # overload per python/importlib_metadata#435 + @overload + def get_all(self, name: str, failobj: None = None) -> Optional[List[Any]]: + ... # pragma: no cover + + @overload + def get_all(self, name: str, failobj: _T) -> Union[List[Any], _T]: """ Return all values associated with a possibly multi-valued key. """ @@ -29,18 +44,19 @@ def json(self) -> Dict[str, Union[str, List[str]]]: """ -class SimplePath(Protocol): +class SimplePath(Protocol[_T]): """ A minimal subset of pathlib.Path required by PathDistribution. """ - def joinpath(self) -> 'SimplePath': + def joinpath(self) -> _T: ... # pragma: no cover - def __truediv__(self) -> 'SimplePath': + def __truediv__(self, other: Union[str, _T]) -> _T: ... # pragma: no cover - def parent(self) -> 'SimplePath': + @property + def parent(self) -> _T: ... # pragma: no cover def read_text(self) -> str: diff --git a/Lib/test/test_importlib/_context.py b/Lib/test/test_importlib/_context.py new file mode 100644 index 000000000000..8a53eb55d150 --- /dev/null +++ b/Lib/test/test_importlib/_context.py @@ -0,0 +1,13 @@ +import contextlib + + +# from jaraco.context 4.3 +class suppress(contextlib.suppress, contextlib.ContextDecorator): + """ + A version of contextlib.suppress with decorator support. + + >>> @suppress(KeyError) + ... def key_error(): + ... {}[''] + >>> key_error() + """ diff --git a/Lib/test/test_importlib/_path.py b/Lib/test/test_importlib/_path.py new file mode 100644 index 000000000000..71a704389b98 --- /dev/null +++ b/Lib/test/test_importlib/_path.py @@ -0,0 +1,109 @@ +# from jaraco.path 3.5 + +import functools +import pathlib +from typing import Dict, Union + +try: + from typing import Protocol, runtime_checkable +except ImportError: # pragma: no cover + # Python 3.7 + from typing_extensions import Protocol, runtime_checkable # type: ignore + + +FilesSpec = Dict[str, Union[str, bytes, 'FilesSpec']] # type: ignore + + + at runtime_checkable +class TreeMaker(Protocol): + def __truediv__(self, *args, **kwargs): + ... # pragma: no cover + + def mkdir(self, **kwargs): + ... # pragma: no cover + + def write_text(self, content, **kwargs): + ... # pragma: no cover + + def write_bytes(self, content): + ... # pragma: no cover + + +def _ensure_tree_maker(obj: Union[str, TreeMaker]) -> TreeMaker: + return obj if isinstance(obj, TreeMaker) else pathlib.Path(obj) # type: ignore + + +def build( + spec: FilesSpec, + prefix: Union[str, TreeMaker] = pathlib.Path(), # type: ignore +): + """ + Build a set of files/directories, as described by the spec. + + Each key represents a pathname, and the value represents + the content. Content may be a nested directory. + + >>> spec = { + ... 'README.txt': "A README file", + ... "foo": { + ... "__init__.py": "", + ... "bar": { + ... "__init__.py": "", + ... }, + ... "baz.py": "# Some code", + ... } + ... } + >>> target = getfixture('tmp_path') + >>> build(spec, target) + >>> target.joinpath('foo/baz.py').read_text(encoding='utf-8') + '# Some code' + """ + for name, contents in spec.items(): + create(contents, _ensure_tree_maker(prefix) / name) + + + at functools.singledispatch +def create(content: Union[str, bytes, FilesSpec], path): + path.mkdir(exist_ok=True) + build(content, prefix=path) # type: ignore + + + at create.register +def _(content: bytes, path): + path.write_bytes(content) + + + at create.register +def _(content: str, path): + path.write_text(content, encoding='utf-8') + + + at create.register +def _(content: str, path): + path.write_text(content, encoding='utf-8') + + +class Recording: + """ + A TreeMaker object that records everything that would be written. + + >>> r = Recording() + >>> build({'foo': {'foo1.txt': 'yes'}, 'bar.txt': 'abc'}, r) + >>> r.record + ['foo/foo1.txt', 'bar.txt'] + """ + + def __init__(self, loc=pathlib.PurePosixPath(), record=None): + self.loc = loc + self.record = record if record is not None else [] + + def __truediv__(self, other): + return Recording(self.loc / other, self.record) + + def write_text(self, content, **kwargs): + self.record.append(str(self.loc)) + + write_bytes = write_text + + def mkdir(self, **kwargs): + return diff --git a/Lib/test/test_importlib/fixtures.py b/Lib/test/test_importlib/fixtures.py index e7be77b3957c..a364a977bce7 100644 --- a/Lib/test/test_importlib/fixtures.py +++ b/Lib/test/test_importlib/fixtures.py @@ -10,7 +10,10 @@ from test.support.os_helper import FS_NONASCII from test.support import requires_zlib -from typing import Dict, Union + +from . import _path +from ._path import FilesSpec + try: from importlib import resources # type: ignore @@ -83,13 +86,8 @@ def setUp(self): self.fixtures.enter_context(self.add_sys_path(self.site_dir)) -# Except for python/mypy#731, prefer to define -# FilesDef = Dict[str, Union['FilesDef', str]] -FilesDef = Dict[str, Union[Dict[str, Union[Dict[str, str], str]], str]] - - class DistInfoPkg(OnSysPath, SiteDir): - files: FilesDef = { + files: FilesSpec = { "distinfo_pkg-1.0.0.dist-info": { "METADATA": """ Name: distinfo-pkg @@ -131,7 +129,7 @@ def make_uppercase(self): class DistInfoPkgWithDot(OnSysPath, SiteDir): - files: FilesDef = { + files: FilesSpec = { "pkg_dot-1.0.0.dist-info": { "METADATA": """ Name: pkg.dot @@ -146,7 +144,7 @@ def setUp(self): class DistInfoPkgWithDotLegacy(OnSysPath, SiteDir): - files: FilesDef = { + files: FilesSpec = { "pkg.dot-1.0.0.dist-info": { "METADATA": """ Name: pkg.dot @@ -173,7 +171,7 @@ def setUp(self): class EggInfoPkg(OnSysPath, SiteDir): - files: FilesDef = { + files: FilesSpec = { "egginfo_pkg.egg-info": { "PKG-INFO": """ Name: egginfo-pkg @@ -212,8 +210,99 @@ def setUp(self): build_files(EggInfoPkg.files, prefix=self.site_dir) +class EggInfoPkgPipInstalledNoToplevel(OnSysPath, SiteDir): + files: FilesSpec = { + "egg_with_module_pkg.egg-info": { + "PKG-INFO": "Name: egg_with_module-pkg", + # SOURCES.txt is made from the source archive, and contains files + # (setup.py) that are not present after installation. + "SOURCES.txt": """ + egg_with_module.py + setup.py + egg_with_module_pkg.egg-info/PKG-INFO + egg_with_module_pkg.egg-info/SOURCES.txt + egg_with_module_pkg.egg-info/top_level.txt + """, + # installed-files.txt is written by pip, and is a strictly more + # accurate source than SOURCES.txt as to the installed contents of + # the package. + "installed-files.txt": """ + ../egg_with_module.py + PKG-INFO + SOURCES.txt + top_level.txt + """, + # missing top_level.txt (to trigger fallback to installed-files.txt) + }, + "egg_with_module.py": """ + def main(): + print("hello world") + """, + } + + def setUp(self): + super().setUp() + build_files(EggInfoPkgPipInstalledNoToplevel.files, prefix=self.site_dir) + + +class EggInfoPkgPipInstalledNoModules(OnSysPath, SiteDir): + files: FilesSpec = { + "egg_with_no_modules_pkg.egg-info": { + "PKG-INFO": "Name: egg_with_no_modules-pkg", + # SOURCES.txt is made from the source archive, and contains files + # (setup.py) that are not present after installation. + "SOURCES.txt": """ + setup.py + egg_with_no_modules_pkg.egg-info/PKG-INFO + egg_with_no_modules_pkg.egg-info/SOURCES.txt + egg_with_no_modules_pkg.egg-info/top_level.txt + """, + # installed-files.txt is written by pip, and is a strictly more + # accurate source than SOURCES.txt as to the installed contents of + # the package. + "installed-files.txt": """ + PKG-INFO + SOURCES.txt + top_level.txt + """, + # top_level.txt correctly reflects that no modules are installed + "top_level.txt": b"\n", + }, + } + + def setUp(self): + super().setUp() + build_files(EggInfoPkgPipInstalledNoModules.files, prefix=self.site_dir) + + +class EggInfoPkgSourcesFallback(OnSysPath, SiteDir): + files: FilesSpec = { + "sources_fallback_pkg.egg-info": { + "PKG-INFO": "Name: sources_fallback-pkg", + # SOURCES.txt is made from the source archive, and contains files + # (setup.py) that are not present after installation. + "SOURCES.txt": """ + sources_fallback.py + setup.py + sources_fallback_pkg.egg-info/PKG-INFO + sources_fallback_pkg.egg-info/SOURCES.txt + """, + # missing installed-files.txt (i.e. not installed by pip) and + # missing top_level.txt (to trigger fallback to SOURCES.txt) + }, + "sources_fallback.py": """ + def main(): + print("hello world") + """, + } + + def setUp(self): + super().setUp() + build_files(EggInfoPkgSourcesFallback.files, prefix=self.site_dir) + + class EggInfoFile(OnSysPath, SiteDir): - files: FilesDef = { + files: FilesSpec = { "egginfo_file.egg-info": """ Metadata-Version: 1.0 Name: egginfo_file @@ -233,38 +322,22 @@ def setUp(self): build_files(EggInfoFile.files, prefix=self.site_dir) -def build_files(file_defs, prefix=pathlib.Path()): - """Build a set of files/directories, as described by the +# dedent all text strings before writing +orig = _path.create.registry[str] +_path.create.register(str, lambda content, path: orig(DALS(content), path)) - file_defs dictionary. Each key/value pair in the dictionary is - interpreted as a filename/contents pair. If the contents value is a - dictionary, a directory is created, and the dictionary interpreted - as the files within it, recursively. - For example: +build_files = _path.build - {"README.txt": "A README file", - "foo": { - "__init__.py": "", - "bar": { - "__init__.py": "", - }, - "baz.py": "# Some code", - } - } - """ - for name, contents in file_defs.items(): - full_name = prefix / name - if isinstance(contents, dict): - full_name.mkdir() - build_files(contents, prefix=full_name) - else: - if isinstance(contents, bytes): - with full_name.open('wb') as f: - f.write(contents) - else: - with full_name.open('w', encoding='utf-8') as f: - f.write(DALS(contents)) + +def build_record(file_defs): + return ''.join(f'{name},,\n' for name in record_names(file_defs)) + + +def record_names(file_defs): + recording = _path.Recording() + _path.build(file_defs, recording) + return recording.record class FileBuilder: diff --git a/Lib/test/test_importlib/test_main.py b/Lib/test/test_importlib/test_main.py index 30b68b6ae7d8..46cd2b696d4c 100644 --- a/Lib/test/test_importlib/test_main.py +++ b/Lib/test/test_importlib/test_main.py @@ -1,7 +1,10 @@ import re import pickle import unittest +import warnings import importlib.metadata +import contextlib +import itertools try: import pyfakefs.fake_filesystem_unittest as ffs @@ -9,6 +12,7 @@ from .stubs import fake_filesystem_unittest as ffs from . import fixtures +from ._context import suppress from importlib.metadata import ( Distribution, EntryPoint, @@ -22,6 +26,13 @@ ) + at contextlib.contextmanager +def suppress_known_deprecation(): + with warnings.catch_warnings(record=True) as ctx: + warnings.simplefilter('default', category=DeprecationWarning) + yield ctx + + class BasicTests(fixtures.DistInfoPkg, unittest.TestCase): version_pattern = r'\d+\.\d+(\.\d)?' @@ -37,7 +48,7 @@ def test_for_name_does_not_exist(self): def test_package_not_found_mentions_metadata(self): """ When a package is not found, that could indicate that the - packgae is not installed or that it is installed without + package is not installed or that it is installed without metadata. Ensure the exception mentions metadata to help guide users toward the cause. See #124. """ @@ -46,8 +57,12 @@ def test_package_not_found_mentions_metadata(self): assert "metadata" in str(ctx.exception) - def test_new_style_classes(self): - self.assertIsInstance(Distribution, type) + # expected to fail until ABC is enforced + @suppress(AssertionError) + @suppress_known_deprecation() + def test_abc_enforced(self): + with self.assertRaises(TypeError): + type('DistributionSubclass', (Distribution,), {})() @fixtures.parameterize( dict(name=None), @@ -172,11 +187,21 @@ def test_metadata_loads_egg_info(self): assert meta['Description'] == 'p?r?tend' -class DiscoveryTests(fixtures.EggInfoPkg, fixtures.DistInfoPkg, unittest.TestCase): +class DiscoveryTests( + fixtures.EggInfoPkg, + fixtures.EggInfoPkgPipInstalledNoToplevel, + fixtures.EggInfoPkgPipInstalledNoModules, + fixtures.EggInfoPkgSourcesFallback, + fixtures.DistInfoPkg, + unittest.TestCase, +): def test_package_discovery(self): dists = list(distributions()) assert all(isinstance(dist, Distribution) for dist in dists) assert any(dist.metadata['Name'] == 'egginfo-pkg' for dist in dists) + assert any(dist.metadata['Name'] == 'egg_with_module-pkg' for dist in dists) + assert any(dist.metadata['Name'] == 'egg_with_no_modules-pkg' for dist in dists) + assert any(dist.metadata['Name'] == 'sources_fallback-pkg' for dist in dists) assert any(dist.metadata['Name'] == 'distinfo-pkg' for dist in dists) def test_invalid_usage(self): @@ -324,3 +349,79 @@ def test_packages_distributions_neither_toplevel_nor_files(self): prefix=self.site_dir, ) packages_distributions() + + def test_packages_distributions_all_module_types(self): + """ + Test top-level modules detected on a package without 'top-level.txt'. + """ + suffixes = importlib.machinery.all_suffixes() + metadata = dict( + METADATA=""" + Name: all_distributions + Version: 1.0.0 + """, + ) + files = { + 'all_distributions-1.0.0.dist-info': metadata, + } + for i, suffix in enumerate(suffixes): + files.update( + { + f'importable-name {i}{suffix}': '', + f'in_namespace_{i}': { + f'mod{suffix}': '', + }, + f'in_package_{i}': { + '__init__.py': '', + f'mod{suffix}': '', + }, + } + ) + metadata.update(RECORD=fixtures.build_record(files)) + fixtures.build_files(files, prefix=self.site_dir) + + distributions = packages_distributions() + + for i in range(len(suffixes)): + assert distributions[f'importable-name {i}'] == ['all_distributions'] + assert distributions[f'in_namespace_{i}'] == ['all_distributions'] + assert distributions[f'in_package_{i}'] == ['all_distributions'] + + assert not any(name.endswith('.dist-info') for name in distributions) + + +class PackagesDistributionsEggTest( + fixtures.EggInfoPkg, + fixtures.EggInfoPkgPipInstalledNoToplevel, + fixtures.EggInfoPkgPipInstalledNoModules, + fixtures.EggInfoPkgSourcesFallback, + unittest.TestCase, +): + def test_packages_distributions_on_eggs(self): + """ + Test old-style egg packages with a variation of 'top_level.txt', + 'SOURCES.txt', and 'installed-files.txt', available. + """ + distributions = packages_distributions() + + def import_names_from_package(package_name): + return { + import_name + for import_name, package_names in distributions.items() + if package_name in package_names + } + + # egginfo-pkg declares one import ('mod') via top_level.txt + assert import_names_from_package('egginfo-pkg') == {'mod'} + + # egg_with_module-pkg has one import ('egg_with_module') inferred from + # installed-files.txt (top_level.txt is missing) + assert import_names_from_package('egg_with_module-pkg') == {'egg_with_module'} + + # egg_with_no_modules-pkg should not be associated with any import names + # (top_level.txt is empty, and installed-files.txt has no .py files) + assert import_names_from_package('egg_with_no_modules-pkg') == set() + + # sources_fallback-pkg has one import ('sources_fallback') inferred from + # SOURCES.txt (top_level.txt and installed-files.txt is missing) + assert import_names_from_package('sources_fallback-pkg') == {'sources_fallback'} diff --git a/Lib/test/test_importlib/test_metadata_api.py b/Lib/test/test_importlib/test_metadata_api.py index 71c47e62d271..33c6e85ee947 100644 --- a/Lib/test/test_importlib/test_metadata_api.py +++ b/Lib/test/test_importlib/test_metadata_api.py @@ -27,12 +27,14 @@ def suppress_known_deprecation(): class APITests( fixtures.EggInfoPkg, + fixtures.EggInfoPkgPipInstalledNoToplevel, + fixtures.EggInfoPkgPipInstalledNoModules, + fixtures.EggInfoPkgSourcesFallback, fixtures.DistInfoPkg, fixtures.DistInfoPkgWithDot, fixtures.EggInfoFile, unittest.TestCase, ): - version_pattern = r'\d+\.\d+(\.\d)?' def test_retrieves_version_of_self(self): @@ -63,15 +65,28 @@ def test_prefix_not_matched(self): distribution(prefix) def test_for_top_level(self): - self.assertEqual( - distribution('egginfo-pkg').read_text('top_level.txt').strip(), 'mod' - ) + tests = [ + ('egginfo-pkg', 'mod'), + ('egg_with_no_modules-pkg', ''), + ] + for pkg_name, expect_content in tests: + with self.subTest(pkg_name): + self.assertEqual( + distribution(pkg_name).read_text('top_level.txt').strip(), + expect_content, + ) def test_read_text(self): - top_level = [ - path for path in files('egginfo-pkg') if path.name == 'top_level.txt' - ][0] - self.assertEqual(top_level.read_text(), 'mod\n') + tests = [ + ('egginfo-pkg', 'mod\n'), + ('egg_with_no_modules-pkg', '\n'), + ] + for pkg_name, expect_content in tests: + with self.subTest(pkg_name): + top_level = [ + path for path in files(pkg_name) if path.name == 'top_level.txt' + ][0] + self.assertEqual(top_level.read_text(), expect_content) def test_entry_points(self): eps = entry_points() @@ -137,6 +152,28 @@ def test_metadata_for_this_package(self): classifiers = md.get_all('Classifier') assert 'Topic :: Software Development :: Libraries' in classifiers + def test_missing_key_legacy(self): + """ + Requesting a missing key will still return None, but warn. + """ + md = metadata('distinfo-pkg') + with suppress_known_deprecation(): + assert md['does-not-exist'] is None + + def test_get_key(self): + """ + Getting a key gets the key. + """ + md = metadata('egginfo-pkg') + assert md.get('Name') == 'egginfo-pkg' + + def test_get_missing_key(self): + """ + Requesting a missing key will return None. + """ + md = metadata('distinfo-pkg') + assert md.get('does-not-exist') is None + @staticmethod def _test_files(files): root = files[0].root @@ -159,6 +196,9 @@ def test_files_dist_info(self): def test_files_egg_info(self): self._test_files(files('egginfo-pkg')) + self._test_files(files('egg_with_module-pkg')) + self._test_files(files('egg_with_no_modules-pkg')) + self._test_files(files('sources_fallback-pkg')) def test_version_egg_info_file(self): self.assertEqual(version('egginfo-file'), '0.1') diff --git a/Misc/NEWS.d/next/Library/2023-04-16-19-48-21.gh-issue-103584.3mBTuM.rst b/Misc/NEWS.d/next/Library/2023-04-16-19-48-21.gh-issue-103584.3mBTuM.rst new file mode 100644 index 000000000000..6d7c93ade9cd --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-16-19-48-21.gh-issue-103584.3mBTuM.rst @@ -0,0 +1,12 @@ +Updated ``importlib.metadata`` with changes from ``importlib_metadata`` 5.2 +through 6.5.0, including: Support ``installed-files.txt`` for +``Distribution.files`` when present. ``PackageMetadata`` now stipulates an +additional ``get`` method allowing for easy querying of metadata keys that +may not be present. ``packages_distributions`` now honors packages and +modules with Python modules that not ``.py`` sources (e.g. ``.pyc``, +``.so``). Expand protocol for ``PackageMetadata.get_all`` to match the +upstream implementation of ``email.message.Message.get_all`` in +python/typeshed#9620. Deprecated use of ``Distribution`` without defining +abstract methods. Deprecated expectation that +``PackageMetadata.__getitem__`` will return ``None`` for missing keys. In +the future, it will raise a ``KeyError``. From webhook-mailer at python.org Fri Apr 21 09:28:36 2023 From: webhook-mailer at python.org (markshannon) Date: Fri, 21 Apr 2023 13:28:36 -0000 Subject: [Python-checkins] gh-103082: Fix shifted field initialization in `instrumentation.c` (GH-103561) Message-ID: https://github.com/python/cpython/commit/a4967d9d5974562dc0b3d2fcb494483cce9b8122 commit: a4967d9d5974562dc0b3d2fcb494483cce9b8122 branch: main author: Oleg Iarygin committer: markshannon date: 2023-04-21T07:27:50-06:00 summary: gh-103082: Fix shifted field initialization in `instrumentation.c` (GH-103561) Fix shifted field initialization in instrumentation.c files: M Python/instrumentation.c diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 853e8a10e814..2a3b2b8ebeea 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -16,14 +16,14 @@ static PyObject DISABLE = { - _PyObject_IMMORTAL_REFCNT, - &PyBaseObject_Type + .ob_refcnt = _PyObject_IMMORTAL_REFCNT, + .ob_type = &PyBaseObject_Type }; PyObject _PyInstrumentation_MISSING = { - _PyObject_IMMORTAL_REFCNT, - &PyBaseObject_Type + .ob_refcnt = _PyObject_IMMORTAL_REFCNT, + .ob_type = &PyBaseObject_Type }; static const int8_t EVENT_FOR_OPCODE[256] = { From webhook-mailer at python.org Fri Apr 21 11:31:10 2023 From: webhook-mailer at python.org (jaraco) Date: Fri, 21 Apr 2023 15:31:10 -0000 Subject: [Python-checkins] gh-103661: Skip failing test on Windows. (#103662) Message-ID: https://github.com/python/cpython/commit/dc328d398d8f65ec6d2fa493e16ceee75f6d774a commit: dc328d398d8f65ec6d2fa493e16ceee75f6d774a branch: main author: Jason R. Coombs committer: jaraco date: 2023-04-21T11:30:30-04:00 summary: gh-103661: Skip failing test on Windows. (#103662) files: M Lib/test/test_importlib/test_metadata_api.py diff --git a/Lib/test/test_importlib/test_metadata_api.py b/Lib/test/test_importlib/test_metadata_api.py index 33c6e85ee947..d9027861848e 100644 --- a/Lib/test/test_importlib/test_metadata_api.py +++ b/Lib/test/test_importlib/test_metadata_api.py @@ -76,12 +76,23 @@ def test_for_top_level(self): expect_content, ) + @staticmethod + def _workaround_103661(tests): + """ + Skip failing test for now is it's failing on buildbot workers. + See https://github.com/python/cpython/issues/103661. + """ + import platform + if platform.system() == 'Windows': + tests.remove(('egg_with_no_modules-pkg', '\n')) + return tests + def test_read_text(self): tests = [ ('egginfo-pkg', 'mod\n'), ('egg_with_no_modules-pkg', '\n'), ] - for pkg_name, expect_content in tests: + for pkg_name, expect_content in self._workaround_103661(tests): with self.subTest(pkg_name): top_level = [ path for path in files(pkg_name) if path.name == 'top_level.txt' From webhook-mailer at python.org Fri Apr 21 21:52:44 2023 From: webhook-mailer at python.org (rhettinger) Date: Sat, 22 Apr 2023 01:52:44 -0000 Subject: [Python-checkins] GH-103415: Document itertools.batched() in whatsnew.3.12 (#103670) Message-ID: https://github.com/python/cpython/commit/0cb0871584d2288e436445ee32e585bf5af7c9de commit: 0cb0871584d2288e436445ee32e585bf5af7c9de branch: main author: Raymond Hettinger committer: rhettinger date: 2023-04-21T20:52:37-05:00 summary: GH-103415: Document itertools.batched() in whatsnew.3.12 (#103670) files: M Doc/whatsnew/3.12.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index b3bb065741d0..f9406653e625 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -309,6 +309,13 @@ fractions * Objects of type :class:`fractions.Fraction` now support float-style formatting. (Contributed by Mark Dickinson in :gh:`100161`.) +itertools +--------- + +* Added :class:`itertools.batched()` for collecting into even-sized + tuples where the last batch may be shorter than the rest. + (Contributed by Raymond Hettinger in :gh:`98363`.) + math ---- From webhook-mailer at python.org Fri Apr 21 21:53:57 2023 From: webhook-mailer at python.org (rhettinger) Date: Sat, 22 Apr 2023 01:53:57 -0000 Subject: [Python-checkins] Minor improvements to the functools docs (#103672) Message-ID: https://github.com/python/cpython/commit/7d20783d45a9c78379fe79229b57e4c31610a623 commit: 7d20783d45a9c78379fe79229b57e4c31610a623 branch: main author: Raymond Hettinger committer: rhettinger date: 2023-04-21T20:53:50-05:00 summary: Minor improvements to the functools docs (#103672) * Use an f-string for improved readability * Put version notes in chronological order files: M Doc/library/functools.rst diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst index d467e50bc7a4..d1289ce83621 100644 --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -118,6 +118,7 @@ The :mod:`functools` module defines the following functions: def stdev(self): return statistics.stdev(self._data) + .. versionadded:: 3.8 .. versionchanged:: 3.12 Prior to Python 3.12, ``cached_property`` included an undocumented lock to @@ -126,8 +127,6 @@ The :mod:`functools` module defines the following functions: per-instance, which could result in unacceptably high lock contention. In Python 3.12+ this locking is removed. - .. versionadded:: 3.8 - .. function:: cmp_to_key(func) @@ -233,7 +232,7 @@ The :mod:`functools` module defines the following functions: @lru_cache(maxsize=32) def get_pep(num): 'Retrieve text of a Python Enhancement Proposal' - resource = 'https://peps.python.org/pep-%04d/' % num + resource = f'https://peps.python.org/pep-{num:04d}' try: with urllib.request.urlopen(resource) as s: return s.read() From webhook-mailer at python.org Sat Apr 22 01:45:21 2023 From: webhook-mailer at python.org (carljm) Date: Sat, 22 Apr 2023 05:45:21 -0000 Subject: [Python-checkins] gh-103556: [inspect.Signature] disallow pos-or-kw params without default after pos-only with default (#103557) Message-ID: https://github.com/python/cpython/commit/6b58d419a1bd62ac94274d108d59980a3eb6f6e0 commit: 6b58d419a1bd62ac94274d108d59980a3eb6f6e0 branch: main author: Nikita Sobolev committer: carljm date: 2023-04-21T23:45:10-06:00 summary: gh-103556: [inspect.Signature] disallow pos-or-kw params without default after pos-only with default (#103557) files: A Misc/NEWS.d/next/Library/2023-04-15-12-19-14.gh-issue-103556.TEf-2m.rst M Lib/inspect.py M Lib/test/test_inspect.py diff --git a/Lib/inspect.py b/Lib/inspect.py index 4242b40c2a08..6d1d7b766cb3 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -3006,7 +3006,7 @@ def __init__(self, parameters=None, *, return_annotation=_empty, if __validate_parameters__: params = OrderedDict() top_kind = _POSITIONAL_ONLY - kind_defaults = False + seen_default = False for param in parameters: kind = param.kind @@ -3021,21 +3021,19 @@ def __init__(self, parameters=None, *, return_annotation=_empty, kind.description) raise ValueError(msg) elif kind > top_kind: - kind_defaults = False top_kind = kind if kind in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD): if param.default is _empty: - if kind_defaults: + if seen_default: # No default for this parameter, but the - # previous parameter of the same kind had - # a default + # previous parameter of had a default msg = 'non-default argument follows default ' \ 'argument' raise ValueError(msg) else: # There is a default for this parameter. - kind_defaults = True + seen_default = True if name in params: msg = 'duplicate parameter name: {!r}'.format(name) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 6b342b1f00d6..42e3d709bd68 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -2463,18 +2463,43 @@ def test_signature_object(self): self.assertEqual(str(S()), '()') self.assertEqual(repr(S().parameters), 'mappingproxy(OrderedDict())') - def test(po, pk, pod=42, pkd=100, *args, ko, **kwargs): + def test(po, /, pk, pkd=100, *args, ko, kod=10, **kwargs): pass + sig = inspect.signature(test) - po = sig.parameters['po'].replace(kind=P.POSITIONAL_ONLY) - pod = sig.parameters['pod'].replace(kind=P.POSITIONAL_ONLY) + self.assertTrue(repr(sig).startswith(' {42:'ham'}: pass foo_partial = functools.partial(foo, a=1) diff --git a/Misc/NEWS.d/next/Library/2023-04-15-12-19-14.gh-issue-103556.TEf-2m.rst b/Misc/NEWS.d/next/Library/2023-04-15-12-19-14.gh-issue-103556.TEf-2m.rst new file mode 100644 index 000000000000..fe2267b7b790 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-15-12-19-14.gh-issue-103556.TEf-2m.rst @@ -0,0 +1,3 @@ +Now creating :class:`inspect.Signature` objects with positional-only +parameter with a default followed by a positional-or-keyword parameter +without one is impossible. From webhook-mailer at python.org Sat Apr 22 07:19:31 2023 From: webhook-mailer at python.org (pfmoore) Date: Sat, 22 Apr 2023 11:19:31 -0000 Subject: [Python-checkins] gh-103559: Update bundled pip version to 23.1.1 (gh-103560) Message-ID: https://github.com/python/cpython/commit/b2862950dc05d313b228f02a8efdd8c9c59a8ff4 commit: b2862950dc05d313b228f02a8efdd8c9c59a8ff4 branch: main author: Paul Moore committer: pfmoore date: 2023-04-22T12:19:23+01:00 summary: gh-103559: Update bundled pip version to 23.1.1 (gh-103560) * Update bundled pip version to 23.1 * Update to pip 23.1.1 files: A Lib/ensurepip/_bundled/pip-23.1.1-py3-none-any.whl A Misc/NEWS.d/next/Library/2023-04-15-11-21-38.gh-issue-103559.a9rYHG.rst D Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl M Lib/ensurepip/__init__.py diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 69b23de9e050..4278422dfacc 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -10,7 +10,7 @@ __all__ = ["version", "bootstrap"] _PACKAGE_NAMES = ('pip',) -_PIP_VERSION = "23.0.1" +_PIP_VERSION = "23.1.1" _PROJECTS = [ ("pip", _PIP_VERSION, "py3"), ] diff --git a/Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl b/Lib/ensurepip/_bundled/pip-23.1.1-py3-none-any.whl similarity index 76% rename from Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl rename to Lib/ensurepip/_bundled/pip-23.1.1-py3-none-any.whl index a855dc40e863..dee4c0304b2c 100644 Binary files a/Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl and b/Lib/ensurepip/_bundled/pip-23.1.1-py3-none-any.whl differ diff --git a/Misc/NEWS.d/next/Library/2023-04-15-11-21-38.gh-issue-103559.a9rYHG.rst b/Misc/NEWS.d/next/Library/2023-04-15-11-21-38.gh-issue-103559.a9rYHG.rst new file mode 100644 index 000000000000..2c9d67e2c4bf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-15-11-21-38.gh-issue-103559.a9rYHG.rst @@ -0,0 +1 @@ +Update the bundled copy of pip to version 23.1.1. From webhook-mailer at python.org Sat Apr 22 09:29:46 2023 From: webhook-mailer at python.org (rhettinger) Date: Sat, 22 Apr 2023 13:29:46 -0000 Subject: [Python-checkins] Descriptor HowTo: Update to include attributes added in Python 3.10 (GH-103666) Message-ID: https://github.com/python/cpython/commit/7b134d3e71af03c4593678f36fbb202cc3650f4e commit: 7b134d3e71af03c4593678f36fbb202cc3650f4e branch: main author: Raymond Hettinger committer: rhettinger date: 2023-04-22T08:29:40-05:00 summary: Descriptor HowTo: Update to include attributes added in Python 3.10 (GH-103666) files: M Doc/howto/descriptor.rst diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst index 74710d9b3fc2..3688c47f0d6e 100644 --- a/Doc/howto/descriptor.rst +++ b/Doc/howto/descriptor.rst @@ -1273,11 +1273,14 @@ Using the non-data descriptor protocol, a pure Python version of .. testcode:: + import functools + class StaticMethod: "Emulate PyStaticMethod_Type() in Objects/funcobject.c" def __init__(self, f): self.f = f + functools.update_wrapper(self, f) def __get__(self, obj, objtype=None): return self.f @@ -1285,13 +1288,19 @@ Using the non-data descriptor protocol, a pure Python version of def __call__(self, *args, **kwds): return self.f(*args, **kwds) +The :func:`functools.update_wrapper` call adds a ``__wrapped__`` attribute +that refers to the underlying function. Also it carries forward +the attributes necessary to make the wrapper look like the wrapped +function: ``__name__``, ``__qualname__``, ``__doc__``, and ``__annotations__``. + .. testcode:: :hide: class E_sim: @StaticMethod - def f(x): - return x * 10 + def f(x: int) -> str: + "Simple function example" + return "!" * x wrapped_ord = StaticMethod(ord) @@ -1299,11 +1308,51 @@ Using the non-data descriptor protocol, a pure Python version of :hide: >>> E_sim.f(3) - 30 + '!!!' >>> E_sim().f(3) - 30 + '!!!' + + >>> sm = vars(E_sim)['f'] + >>> type(sm).__name__ + 'StaticMethod' + >>> f = E_sim.f + >>> type(f).__name__ + 'function' + >>> sm.__name__ + 'f' + >>> f.__name__ + 'f' + >>> sm.__qualname__ + 'E_sim.f' + >>> f.__qualname__ + 'E_sim.f' + >>> sm.__doc__ + 'Simple function example' + >>> f.__doc__ + 'Simple function example' + >>> sm.__annotations__ + {'x': , 'return': } + >>> f.__annotations__ + {'x': , 'return': } + >>> sm.__module__ == f.__module__ + True + >>> sm(3) + '!!!' + >>> f(3) + '!!!' + >>> wrapped_ord('A') 65 + >>> wrapped_ord.__module__ == ord.__module__ + True + >>> wrapped_ord.__wrapped__ == ord + True + >>> wrapped_ord.__name__ == ord.__name__ + True + >>> wrapped_ord.__qualname__ == ord.__qualname__ + True + >>> wrapped_ord.__doc__ == ord.__doc__ + True Class methods @@ -1359,11 +1408,14 @@ Using the non-data descriptor protocol, a pure Python version of .. testcode:: + import functools + class ClassMethod: "Emulate PyClassMethod_Type() in Objects/funcobject.c" def __init__(self, f): self.f = f + functools.update_wrapper(self, f) def __get__(self, obj, cls=None): if cls is None: @@ -1380,8 +1432,9 @@ Using the non-data descriptor protocol, a pure Python version of # Verify the emulation works class T: @ClassMethod - def cm(cls, x, y): - return (cls, x, y) + def cm(cls, x: int, y: str) -> tuple[str, int, str]: + "Class method that returns a tuple" + return (cls.__name__, x, y) @ClassMethod @property @@ -1393,17 +1446,40 @@ Using the non-data descriptor protocol, a pure Python version of :hide: >>> T.cm(11, 22) - (, 11, 22) + ('T', 11, 22) # Also call it from an instance >>> t = T() >>> t.cm(11, 22) - (, 11, 22) + ('T', 11, 22) # Check the alternate path for chained descriptors >>> T.__doc__ "A doc for 'T'" + # Verify that T uses our emulation + >>> type(vars(T)['cm']).__name__ + 'ClassMethod' + + # Verify that update_wrapper() correctly copied attributes + >>> T.cm.__name__ + 'cm' + >>> T.cm.__qualname__ + 'T.cm' + >>> T.cm.__doc__ + 'Class method that returns a tuple' + >>> T.cm.__annotations__ + {'x': , 'y': , 'return': tuple[str, int, str]} + + # Verify that __wrapped__ was added and works correctly + >>> f = vars(T)['cm'].__wrapped__ + >>> type(f).__name__ + 'function' + >>> f.__name__ + 'cm' + >>> f(T, 11, 22) + ('T', 11, 22) + The code path for ``hasattr(type(self.f), '__get__')`` was added in Python 3.9 and makes it possible for :func:`classmethod` to support @@ -1423,6 +1499,12 @@ chained together. In Python 3.11, this functionality was deprecated. >>> G.__doc__ "A doc for 'G'" +The :func:`functools.update_wrapper` call in ``ClassMethod`` adds a +``__wrapped__`` attribute that refers to the underlying function. Also +it carries forward the attributes necessary to make the wrapper look +like the wrapped function: ``__name__``, ``__qualname__``, ``__doc__``, +and ``__annotations__``. + Member objects and __slots__ ---------------------------- From webhook-mailer at python.org Sat Apr 22 10:18:32 2023 From: webhook-mailer at python.org (rhettinger) Date: Sat, 22 Apr 2023 14:18:32 -0000 Subject: [Python-checkins] GH-103475: cache() and lru_cache() do not have a "call once" guarantee (GH-103669) Message-ID: https://github.com/python/cpython/commit/e5eaac6064561c8f7643011a31fa506e78330798 commit: e5eaac6064561c8f7643011a31fa506e78330798 branch: main author: Raymond Hettinger committer: rhettinger date: 2023-04-22T09:18:25-05:00 summary: GH-103475: cache() and lru_cache() do not have a "call once" guarantee (GH-103669) files: M Doc/library/functools.rst diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst index d1289ce83621..29cbc87bf66d 100644 --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -49,8 +49,13 @@ The :mod:`functools` module defines the following functions: >>> factorial(12) # makes two new recursive calls, the other 10 are cached 479001600 - The cache is threadsafe so the wrapped function can be used in multiple - threads. + The cache is threadsafe so that the wrapped function can be used in + multiple threads. This means that the underlying data structure will + remain coherent during concurrent updates. + + It is possible for the wrapped function to be called more than once if + another thread makes an additional call before the initial call has been + completed and cached. .. versionadded:: 3.9 @@ -158,8 +163,13 @@ The :mod:`functools` module defines the following functions: *maxsize* most recent calls. It can save time when an expensive or I/O bound function is periodically called with the same arguments. - The cache is threadsafe so the wrapped function can be used in multiple - threads. + The cache is threadsafe so that the wrapped function can be used in + multiple threads. This means that the underlying data structure will + remain coherent during concurrent updates. + + It is possible for the wrapped function to be called more than once if + another thread makes an additional call before the initial call has been + completed and cached. Since a dictionary is used to cache results, the positional and keyword arguments to the function must be :term:`hashable`. From webhook-mailer at python.org Sat Apr 22 10:24:54 2023 From: webhook-mailer at python.org (hugovk) Date: Sat, 22 Apr 2023 14:24:54 -0000 Subject: [Python-checkins] GH-103484: Fix broken links reported by linkcheck (#103608) Message-ID: https://github.com/python/cpython/commit/caed49448d195565940caf198cf0edda65ee5679 commit: caed49448d195565940caf198cf0edda65ee5679 branch: main author: Rafael Fontenelle committer: hugovk date: 2023-04-22T08:24:47-06:00 summary: GH-103484: Fix broken links reported by linkcheck (#103608) * Doc: Fix broken links reported by linkcheck * Apply suggestions from code review - Remove extra diff line in faq/library.rst (merwok) - Use HTTPS to link Unicode 15.0.0 to solve a redirect (hugovk) - Use wayback machine link for openssl 1.1.0 instead of linking 1.1.1, "as this text mentions a feature from 1.1.0" (hugovk) Co-authored-by: ?ric Co-authored-by: Hugo van Kemenade * Doc: Make mark-up code as literal * Doc: Alphabetize items in linkcheck_ignore Co-authored-by: Hugo van Kemenade * Doc: Improve comment in sphinx conf Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> --------- Co-authored-by: ?ric Co-authored-by: Hugo van Kemenade Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/conf.py M Doc/distributing/index.rst M Doc/faq/library.rst M Doc/howto/functional.rst M Doc/howto/urllib2.rst M Doc/library/readline.rst M Doc/library/stdtypes.rst M Doc/library/zipfile.rst M Doc/whatsnew/2.6.rst M Doc/whatsnew/2.7.rst M Misc/NEWS.d/3.7.0b2.rst M Misc/NEWS.d/3.8.0a1.rst M Misc/NEWS.d/3.9.0a1.rst M Misc/NEWS.d/3.9.0a2.rst M Misc/NEWS.d/3.9.0a4.rst diff --git a/Doc/conf.py b/Doc/conf.py index 60404fd3829e..4c120bee64dd 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -263,6 +263,24 @@ r'https://github.com/python/cpython/tree/.*': 'https://github.com/python/cpython/blob/.*' } +linkcheck_anchors_ignore = [ + # ignore anchors that start with a '/', e.g. Wikipedia media files: + # https://en.wikipedia.org/wiki/Walrus#/media/File:Pacific_Walrus_-_Bull_(8247646168).jpg + r'\/.*', +] + +linkcheck_ignore = [ + # The crawler gets "Anchor not found" + r'https://developer.apple.com/documentation/.+?#.*', + r'https://devguide.python.org.+?/#.*', + r'https://github.com.+?#.*', + # Robot crawlers not allowed: "403 Client Error: Forbidden" + r'https://support.enthought.com/hc/.*', + # SSLError CertificateError, even though it is valid + r'https://unix.org/version2/whatsnew/lp64_wp.html', +] + + # Options for extensions # ---------------------- diff --git a/Doc/distributing/index.rst b/Doc/distributing/index.rst index 21389adedf9c..d237f8f082d8 100644 --- a/Doc/distributing/index.rst +++ b/Doc/distributing/index.rst @@ -129,14 +129,10 @@ involved in creating and publishing a project: * `Uploading the project to the Python Package Index`_ * `The .pypirc file`_ -.. _Project structure: \ - https://packaging.python.org/tutorials/packaging-projects/#packaging-python-projects -.. _Building and packaging the project: \ - https://packaging.python.org/tutorials/packaging-projects/#creating-the-package-files -.. _Uploading the project to the Python Package Index: \ - https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives -.. _The .pypirc file: \ - https://packaging.python.org/specifications/pypirc/ +.. _Project structure: https://packaging.python.org/tutorials/packaging-projects/#packaging-python-projects +.. _Building and packaging the project: https://packaging.python.org/tutorials/packaging-projects/#creating-the-package-files +.. _Uploading the project to the Python Package Index: https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives +.. _The .pypirc file: https://packaging.python.org/specifications/pypirc/ How do I...? diff --git a/Doc/faq/library.rst b/Doc/faq/library.rst index a9cde4565750..597caaa778e1 100644 --- a/Doc/faq/library.rst +++ b/Doc/faq/library.rst @@ -780,7 +780,7 @@ socket to :meth:`select.select` to check if it's writable. The :mod:`asyncio` module provides a general purpose single-threaded and concurrent asynchronous library, which can be used for writing non-blocking network code. - The third-party `Twisted `_ library is + The third-party `Twisted `_ library is a popular and feature-rich alternative. diff --git a/Doc/howto/functional.rst b/Doc/howto/functional.rst index 38a651b0f964..5cf12cc52bde 100644 --- a/Doc/howto/functional.rst +++ b/Doc/howto/functional.rst @@ -1208,8 +1208,8 @@ General ------- **Structure and Interpretation of Computer Programs**, by Harold Abelson and -Gerald Jay Sussman with Julie Sussman. Full text at -https://mitpress.mit.edu/sicp/. In this classic textbook of computer science, +Gerald Jay Sussman with Julie Sussman. The book can be found at +https://mitpress.mit.edu/sicp. In this classic textbook of computer science, chapters 2 and 3 discuss the use of sequences and streams to organize the data flow inside a program. The book uses Scheme for its examples, but many of the design approaches described in these chapters are applicable to functional-style diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst index 69af3c3a85c5..61ba6bd7224f 100644 --- a/Doc/howto/urllib2.rst +++ b/Doc/howto/urllib2.rst @@ -86,7 +86,7 @@ response:: import urllib.request - req = urllib.request.Request('http://www.voidspace.org.uk') + req = urllib.request.Request('http://python.org/') with urllib.request.urlopen(req) as response: the_page = response.read() @@ -458,7 +458,7 @@ To illustrate creating and installing a handler we will use the ``HTTPBasicAuthHandler``. For a more detailed discussion of this subject -- including an explanation of how Basic Authentication works - see the `Basic Authentication Tutorial -`_. +`__. When authentication is required, the server sends a header (as well as the 401 error code) requesting authentication. This specifies the authentication scheme diff --git a/Doc/library/readline.rst b/Doc/library/readline.rst index 4d485d25b540..8fb0eca8df74 100644 --- a/Doc/library/readline.rst +++ b/Doc/library/readline.rst @@ -19,7 +19,7 @@ function. Readline keybindings may be configured via an initialization file, typically ``.inputrc`` in your home directory. See `Readline Init File -`_ +`_ in the GNU Readline manual for information about the format and allowable constructs of that file, and the capabilities of the Readline library in general. diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index bcfc6e5cfce6..aea2410bae35 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -1605,8 +1605,8 @@ expression support in the :mod:`re` module). converts it to ``"ss"``. The casefolding algorithm is - `described in section 3.13 of the Unicode Standard - `__. + `described in section 3.13 'Default Case Folding' of the Unicode Standard + `__. .. versionadded:: 3.3 @@ -1768,8 +1768,9 @@ expression support in the :mod:`re` module). one character, ``False`` otherwise. Alphabetic characters are those characters defined in the Unicode character database as "Letter", i.e., those with general category property being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is different - from the `Alphabetic property defined in the Unicode Standard - `_. + from the `Alphabetic property defined in the section 4.10 'Letters, Alphabetic, and + Ideographic' of the Unicode Standard + `_. .. method:: str.isascii() @@ -1904,8 +1905,8 @@ expression support in the :mod:`re` module). lowercase. The lowercasing algorithm used is - `described in section 3.13 of the Unicode Standard - `__. + `described in section 3.13 'Default Case Folding' of the Unicode Standard + `__. .. method:: str.lstrip([chars]) @@ -2250,8 +2251,8 @@ expression support in the :mod:`re` module). titlecase). The uppercasing algorithm used is - `described in section 3.13 of the Unicode Standard - `__. + `described in section 3.13 'Default Case Folding' of the Unicode Standard + `__. .. method:: str.zfill(width) diff --git a/Doc/library/zipfile.rst b/Doc/library/zipfile.rst index e2a085d6e98e..6f4826cb065c 100644 --- a/Doc/library/zipfile.rst +++ b/Doc/library/zipfile.rst @@ -7,7 +7,7 @@ .. moduleauthor:: James C. Ahlstrom .. sectionauthor:: James C. Ahlstrom -**Source code:** :source:`Lib/zipfile.py` +**Source code:** :source:`Lib/zipfile/` -------------- diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 34f2656f765c..4ee2aacb108a 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -172,7 +172,7 @@ this edition of "What's New in Python" links to the bug/patch item for each change. Hosting of the Python bug tracker is kindly provided by -`Upfront Systems `__ +`Upfront Systems `__ of Stellenbosch, South Africa. Martin von L?wis put a lot of effort into importing existing bugs and patches from SourceForge; his scripts for this import operation are at diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index 810a2cd2537c..36afcb163f1a 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -2104,7 +2104,7 @@ Changes to Python's build process and to the C API include: * The latest release of the GNU Debugger, GDB 7, can be `scripted using Python - `__. + `__. When you begin debugging an executable program P, GDB will look for a file named ``P-gdb.py`` and automatically read it. Dave Malcolm contributed a :file:`python-gdb.py` that adds a number of diff --git a/Misc/NEWS.d/3.7.0b2.rst b/Misc/NEWS.d/3.7.0b2.rst index b2ade206bd5f..9590914599bb 100644 --- a/Misc/NEWS.d/3.7.0b2.rst +++ b/Misc/NEWS.d/3.7.0b2.rst @@ -357,7 +357,7 @@ Wirtel Add TLSVersion constants and SSLContext.maximum_version / minimum_version attributes. The new API wraps OpenSSL 1.1 -https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_min_proto_version.html +https://web.archive.org/web/20180309043602/https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_min_proto_version.html feature. .. diff --git a/Misc/NEWS.d/3.8.0a1.rst b/Misc/NEWS.d/3.8.0a1.rst index 991bbc128670..db2eba32e6ea 100644 --- a/Misc/NEWS.d/3.8.0a1.rst +++ b/Misc/NEWS.d/3.8.0a1.rst @@ -5951,7 +5951,7 @@ Wirtel Add TLSVersion constants and SSLContext.maximum_version / minimum_version attributes. The new API wraps OpenSSL 1.1 -https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_min_proto_version.html +https://web.archive.org/web/20180309043602/https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_min_proto_version.html feature. .. diff --git a/Misc/NEWS.d/3.9.0a1.rst b/Misc/NEWS.d/3.9.0a1.rst index 633620583838..0888a5c43087 100644 --- a/Misc/NEWS.d/3.9.0a1.rst +++ b/Misc/NEWS.d/3.9.0a1.rst @@ -4887,7 +4887,7 @@ Fix use of registry values to launch Python from Microsoft Store app. .. section: Windows Fix memory leak on Windows in creating an SSLContext object or running -urllib.request.urlopen('https://...'). +``urllib.request.urlopen('https://...')``. .. diff --git a/Misc/NEWS.d/3.9.0a2.rst b/Misc/NEWS.d/3.9.0a2.rst index 226ea0d3df22..a03eb10f1d52 100644 --- a/Misc/NEWS.d/3.9.0a2.rst +++ b/Misc/NEWS.d/3.9.0a2.rst @@ -686,7 +686,7 @@ added. Update documentation to state that to activate virtual environments under fish one should use `source`, not `.` as documented at -https://fishshell.com/docs/current/commands.html#source. +https://fishshell.com/docs/current/cmds/source.html. .. diff --git a/Misc/NEWS.d/3.9.0a4.rst b/Misc/NEWS.d/3.9.0a4.rst index 2aef8b26b016..019b34c4082d 100644 --- a/Misc/NEWS.d/3.9.0a4.rst +++ b/Misc/NEWS.d/3.9.0a4.rst @@ -392,7 +392,7 @@ The distutils ``bdist_msi`` command is deprecated in Python 3.9, use Improved performance of zipfile.Path for files with a large number of entries. Also improved performance and fixed minor issue as published with `importlib_metadata 1.5 -`_. +`_. .. From webhook-mailer at python.org Sat Apr 22 11:13:08 2023 From: webhook-mailer at python.org (carljm) Date: Sat, 22 Apr 2023 15:13:08 -0000 Subject: [Python-checkins] [3.11] gh-103556: [inspect.Signature] disallow pos-or-kw params without default after pos-only with default (GH-103557) (#103675) Message-ID: https://github.com/python/cpython/commit/b2fdae9d86cd91fc75ca6a91f772cf805d536f42 commit: b2fdae9d86cd91fc75ca6a91f772cf805d536f42 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: carljm date: 2023-04-22T09:13:02-06:00 summary: [3.11] gh-103556: [inspect.Signature] disallow pos-or-kw params without default after pos-only with default (GH-103557) (#103675) files: A Misc/NEWS.d/next/Library/2023-04-15-12-19-14.gh-issue-103556.TEf-2m.rst M Lib/inspect.py M Lib/test/test_inspect.py diff --git a/Lib/inspect.py b/Lib/inspect.py index bc49e680122d..75d33f2ce7e7 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2978,7 +2978,7 @@ def __init__(self, parameters=None, *, return_annotation=_empty, if __validate_parameters__: params = OrderedDict() top_kind = _POSITIONAL_ONLY - kind_defaults = False + seen_default = False for param in parameters: kind = param.kind @@ -2993,21 +2993,19 @@ def __init__(self, parameters=None, *, return_annotation=_empty, kind.description) raise ValueError(msg) elif kind > top_kind: - kind_defaults = False top_kind = kind if kind in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD): if param.default is _empty: - if kind_defaults: + if seen_default: # No default for this parameter, but the - # previous parameter of the same kind had - # a default + # previous parameter of had a default msg = 'non-default argument follows default ' \ 'argument' raise ValueError(msg) else: # There is a default for this parameter. - kind_defaults = True + seen_default = True if name in params: msg = 'duplicate parameter name: {!r}'.format(name) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 9f597e295445..efcbd63450b3 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -2301,18 +2301,43 @@ def test_signature_object(self): self.assertEqual(str(S()), '()') self.assertEqual(repr(S().parameters), 'mappingproxy(OrderedDict())') - def test(po, pk, pod=42, pkd=100, *args, ko, **kwargs): + def test(po, /, pk, pkd=100, *args, ko, kod=10, **kwargs): pass + sig = inspect.signature(test) - po = sig.parameters['po'].replace(kind=P.POSITIONAL_ONLY) - pod = sig.parameters['pod'].replace(kind=P.POSITIONAL_ONLY) + self.assertTrue(repr(sig).startswith(' {42:'ham'}: pass foo_partial = functools.partial(foo, a=1) diff --git a/Misc/NEWS.d/next/Library/2023-04-15-12-19-14.gh-issue-103556.TEf-2m.rst b/Misc/NEWS.d/next/Library/2023-04-15-12-19-14.gh-issue-103556.TEf-2m.rst new file mode 100644 index 000000000000..fe2267b7b790 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-15-12-19-14.gh-issue-103556.TEf-2m.rst @@ -0,0 +1,3 @@ +Now creating :class:`inspect.Signature` objects with positional-only +parameter with a default followed by a positional-or-keyword parameter +without one is impossible. From webhook-mailer at python.org Sat Apr 22 11:55:06 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sat, 22 Apr 2023 15:55:06 -0000 Subject: [Python-checkins] [3.11] GH-103475: cache() and lru_cache() do not have a "call once" guarantee (GH-103669) (#103682) Message-ID: https://github.com/python/cpython/commit/7f6710bab62f8c30eb432b5024075ae5bf98aef7 commit: 7f6710bab62f8c30eb432b5024075ae5bf98aef7 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: AlexWaygood date: 2023-04-22T09:54:58-06:00 summary: [3.11] GH-103475: cache() and lru_cache() do not have a "call once" guarantee (GH-103669) (#103682) GH-103475: cache() and lru_cache() do not have a "call once" guarantee (GH-103669) (cherry picked from commit e5eaac6064561c8f7643011a31fa506e78330798) Co-authored-by: Raymond Hettinger files: M Doc/library/functools.rst diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst index 80a405e87d8d..7438d4cdadc5 100644 --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -49,8 +49,13 @@ The :mod:`functools` module defines the following functions: >>> factorial(12) # makes two new recursive calls, the other 10 are cached 479001600 - The cache is threadsafe so the wrapped function can be used in multiple - threads. + The cache is threadsafe so that the wrapped function can be used in + multiple threads. This means that the underlying data structure will + remain coherent during concurrent updates. + + It is possible for the wrapped function to be called more than once if + another thread makes an additional call before the initial call has been + completed and cached. .. versionadded:: 3.9 @@ -143,8 +148,13 @@ The :mod:`functools` module defines the following functions: *maxsize* most recent calls. It can save time when an expensive or I/O bound function is periodically called with the same arguments. - The cache is threadsafe so the wrapped function can be used in multiple - threads. + The cache is threadsafe so that the wrapped function can be used in + multiple threads. This means that the underlying data structure will + remain coherent during concurrent updates. + + It is possible for the wrapped function to be called more than once if + another thread makes an additional call before the initial call has been + completed and cached. Since a dictionary is used to cache results, the positional and keyword arguments to the function must be :term:`hashable`. From webhook-mailer at python.org Sat Apr 22 12:32:54 2023 From: webhook-mailer at python.org (mdickinson) Date: Sat, 22 Apr 2023 16:32:54 -0000 Subject: [Python-checkins] gh-83791: Raise TypeError for len(memoryview_0d) (#18463) Message-ID: https://github.com/python/cpython/commit/3d2a46845b67407e2436d910b2e1740c34f4f10d commit: 3d2a46845b67407e2436d910b2e1740c34f4f10d branch: main author: Eric Wieser committer: mdickinson date: 2023-04-22T17:32:47+01:00 summary: gh-83791: Raise TypeError for len(memoryview_0d) (#18463) Changes the behaviour of `len` on a zero-dimensional `memoryview` to raise `TypeError`. Previously, `len` would return `1`. files: A Misc/NEWS.d/next/Core and Builtins/2020-02-11-15-54-40.bpo-39610.fvgsCl.rst M Doc/library/stdtypes.rst M Lib/test/test_buffer.py M Lib/test/test_ctypes/test_pep3118.py M Objects/memoryobject.c diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index aea2410bae35..2360472b31f1 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -3715,12 +3715,15 @@ copying. types such as :class:`bytes` and :class:`bytearray`, an element is a single byte, but other types such as :class:`array.array` may have bigger elements. - ``len(view)`` is equal to the length of :class:`~memoryview.tolist`. - If ``view.ndim = 0``, the length is 1. If ``view.ndim = 1``, the length - is equal to the number of elements in the view. For higher dimensions, - the length is equal to the length of the nested list representation of - the view. The :class:`~memoryview.itemsize` attribute will give you the - number of bytes in a single element. + ``len(view)`` is equal to the length of :class:`~memoryview.tolist`, which + is the nested list representation of the view. If ``view.ndim = 1``, + this is equal to the number of elements in the view. + + .. versionchanged:: 3.12 + If ``view.ndim == 0``, ``len(view)`` now raises :exc:`TypeError` instead of returning 1. + + The :class:`~memoryview.itemsize` attribute will give you the number of + bytes in a single element. A :class:`memoryview` supports slicing and indexing to expose its data. One-dimensional slicing will result in a subview:: diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index 8ac3b7e7eb29..098d2d999643 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -965,8 +965,10 @@ def check_memoryview(m, expected_readonly=readonly): self.assertEqual(m.strides, tuple(strides)) self.assertEqual(m.suboffsets, tuple(suboffsets)) - n = 1 if ndim == 0 else len(lst) - self.assertEqual(len(m), n) + if ndim == 0: + self.assertRaises(TypeError, len, m) + else: + self.assertEqual(len(m), len(lst)) rep = result.tolist() if fmt else result.tobytes() self.assertEqual(rep, lst) diff --git a/Lib/test/test_ctypes/test_pep3118.py b/Lib/test/test_ctypes/test_pep3118.py index c8a70e3e3356..038161745df9 100644 --- a/Lib/test/test_ctypes/test_pep3118.py +++ b/Lib/test/test_ctypes/test_pep3118.py @@ -28,7 +28,7 @@ def test_native_types(self): if shape: self.assertEqual(len(v), shape[0]) else: - self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob)) + self.assertRaises(TypeError, len, v) self.assertEqual(v.itemsize, sizeof(itemtp)) self.assertEqual(v.shape, shape) # XXX Issue #12851: PyCData_NewGetBuffer() must provide strides @@ -39,11 +39,10 @@ def test_native_types(self): # they are always read/write self.assertFalse(v.readonly) - if v.shape: - n = 1 - for dim in v.shape: - n = n * dim - self.assertEqual(n * v.itemsize, len(v.tobytes())) + n = 1 + for dim in v.shape: + n = n * dim + self.assertEqual(n * v.itemsize, len(v.tobytes())) except: # so that we can see the failing type print(tp) @@ -58,7 +57,7 @@ def test_endian_types(self): if shape: self.assertEqual(len(v), shape[0]) else: - self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob)) + self.assertRaises(TypeError, len, v) self.assertEqual(v.itemsize, sizeof(itemtp)) self.assertEqual(v.shape, shape) # XXX Issue #12851 @@ -67,11 +66,10 @@ def test_endian_types(self): # they are always read/write self.assertFalse(v.readonly) - if v.shape: - n = 1 - for dim in v.shape: - n = n * dim - self.assertEqual(n, len(v)) + n = 1 + for dim in v.shape: + n = n * dim + self.assertEqual(n * v.itemsize, len(v.tobytes())) except: # so that we can see the failing type print(tp) @@ -243,7 +241,7 @@ class LEPoint(LittleEndianStructure): # endian_types = [ (BEPoint, "T{>l:x:>l:y:}".replace('l', s_long), (), BEPoint), - (LEPoint, "T{l:x:>l:y:}".replace('l', s_long), (), POINTER(BEPoint)), (POINTER(LEPoint), "&T{view.ndim == 0 ? 1 : self->view.shape[0]; + if (self->view.ndim == 0) { + PyErr_SetString(PyExc_TypeError, "0-dim memory has no length"); + return -1; + } + return self->view.shape[0]; } /* As mapping */ From webhook-mailer at python.org Sat Apr 22 13:53:29 2023 From: webhook-mailer at python.org (jaraco) Date: Sat, 22 Apr 2023 17:53:29 -0000 Subject: [Python-checkins] gh-103661: Apply bugfix from importlib_metadata 6.5.1 and restore test. (#103681) Message-ID: https://github.com/python/cpython/commit/916de04fd1838530096336aadb3b94b774ed6c90 commit: 916de04fd1838530096336aadb3b94b774ed6c90 branch: main author: Jason R. Coombs committer: jaraco date: 2023-04-22T13:52:51-04:00 summary: gh-103661: Apply bugfix from importlib_metadata 6.5.1 and restore test. (#103681) files: M Lib/importlib/metadata/__init__.py M Lib/test/test_importlib/test_metadata_api.py diff --git a/Lib/importlib/metadata/__init__.py b/Lib/importlib/metadata/__init__.py index b8eb19d05dcc..82e0ce1b281c 100644 --- a/Lib/importlib/metadata/__init__.py +++ b/Lib/importlib/metadata/__init__.py @@ -516,27 +516,29 @@ def _read_files_egginfo_installed(self): """ Read installed-files.txt and return lines in a similar CSV-parsable format as RECORD: each file must be placed - relative to the site-packages directory, and must also be + relative to the site-packages directory and must also be quoted (since file names can contain literal commas). This file is written when the package is installed by pip, but it might not be written for other installation methods. - Hence, even if we can assume that this file is accurate - when it exists, we cannot assume that it always exists. + Assume the file is accurate if it exists. """ text = self.read_text('installed-files.txt') - # We need to prepend the .egg-info/ subdir to the lines in this file. - # But this subdir is only available in the PathDistribution's self._path - # which is not easily accessible from this base class... + # Prepend the .egg-info/ subdir to the lines in this file. + # But this subdir is only available from PathDistribution's + # self._path. subdir = getattr(self, '_path', None) if not text or not subdir: return - with contextlib.suppress(Exception): - ret = [ - str((subdir / line).resolve().relative_to(self.locate_file(''))) - for line in text.splitlines() - ] - return map('"{}"'.format, ret) + + paths = ( + (subdir / name) + .resolve() + .relative_to(self.locate_file('').resolve()) + .as_posix() + for name in text.splitlines() + ) + return map('"{}"'.format, paths) def _read_files_egginfo_sources(self): """ diff --git a/Lib/test/test_importlib/test_metadata_api.py b/Lib/test/test_importlib/test_metadata_api.py index d9027861848e..33c6e85ee947 100644 --- a/Lib/test/test_importlib/test_metadata_api.py +++ b/Lib/test/test_importlib/test_metadata_api.py @@ -76,23 +76,12 @@ def test_for_top_level(self): expect_content, ) - @staticmethod - def _workaround_103661(tests): - """ - Skip failing test for now is it's failing on buildbot workers. - See https://github.com/python/cpython/issues/103661. - """ - import platform - if platform.system() == 'Windows': - tests.remove(('egg_with_no_modules-pkg', '\n')) - return tests - def test_read_text(self): tests = [ ('egginfo-pkg', 'mod\n'), ('egg_with_no_modules-pkg', '\n'), ] - for pkg_name, expect_content in self._workaround_103661(tests): + for pkg_name, expect_content in tests: with self.subTest(pkg_name): top_level = [ path for path in files(pkg_name) if path.name == 'top_level.txt' From webhook-mailer at python.org Sat Apr 22 15:39:45 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Sat, 22 Apr 2023 19:39:45 -0000 Subject: [Python-checkins] gh-84436: Implement Immortal Objects (gh-19474) Message-ID: https://github.com/python/cpython/commit/ea2c0016502472aa8baa3149050ada776d17a009 commit: ea2c0016502472aa8baa3149050ada776d17a009 branch: main author: Eddie Elizondo committer: ericsnowcurrently date: 2023-04-22T13:39:37-06:00 summary: gh-84436: Implement Immortal Objects (gh-19474) This is the implementation of PEP683 Motivation: The PR introduces the ability to immortalize instances in CPython which bypasses reference counting. Tagging objects as immortal allows up to skip certain operations when we know that the object will be around for the entire execution of the runtime. Note that this by itself will bring a performance regression to the runtime due to the extra reference count checks. However, this brings the ability of having truly immutable objects that are useful in other contexts such as immutable data sharing between sub-interpreters. files: A Misc/NEWS.d/next/Core and Builtins/2023-04-02-22-14-57.gh-issue-84436.hvMgwF.rst M Doc/library/sys.rst M Doc/whatsnew/3.12.rst M Include/boolobject.h M Include/cpython/unicodeobject.h M Include/internal/pycore_global_objects_fini_generated.h M Include/internal/pycore_long.h M Include/internal/pycore_object.h M Include/internal/pycore_runtime_init.h M Include/internal/pycore_unicodeobject.h M Include/object.h M Include/pyport.h M Lib/test/_test_embed_structseq.py M Lib/test/libregrtest/refleak.py M Lib/test/test_builtin.py M Lib/test/test_ctypes/test_python_api.py M Lib/test/test_sys.py M Lib/test/test_venv.py M Modules/gcmodule.c M Objects/boolobject.c M Objects/bytes_methods.c M Objects/longobject.c M Objects/object.c M Objects/setobject.c M Objects/sliceobject.c M Objects/typeobject.c M Objects/unicodeobject.c M Programs/_testembed.c M Python/ceval.c M Python/clinic/sysmodule.c.h M Python/instrumentation.c M Python/legacy_tracing.c M Python/pylifecycle.c M Python/sysmodule.c M Tools/build/deepfreeze.py diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index e37d57edce51..7324f3113e0a 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -670,6 +670,13 @@ always available. .. versionadded:: 3.4 +.. function:: getunicodeinternedsize() + + Return the number of unicode objects that have been interned. + + .. versionadded:: 3.12 + + .. function:: getandroidapilevel() Return the build time API version of Android as an integer. diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index f9406653e625..b98b7151a321 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1129,6 +1129,24 @@ New Features to replace the legacy-api :c:func:`!PyErr_Display`. (Contributed by Irit Katriel in :gh:`102755`). +* :pep:`683`: Introduced Immortal Objects to Python which allows objects + to bypass reference counts and introduced changes to the C-API: + + - ``_Py_IMMORTAL_REFCNT``: The reference count that defines an object + as immortal. + - ``_Py_IsImmortal`` Checks if an object has the immortal reference count. + - ``PyObject_HEAD_INIT`` This will now initialize reference count to + ``_Py_IMMORTAL_REFCNT`` when used with ``Py_BUILD_CORE``. + - ``SSTATE_INTERNED_IMMORTAL`` An identifier for interned unicode objects + that are immortal. + - ``SSTATE_INTERNED_IMMORTAL_STATIC`` An identifier for interned unicode + objects that are immortal and static + - ``sys.getunicodeinternedsize`` This returns the total number of unicode + objects that have been interned. This is now needed for refleak.py to + correctly track reference counts and allocated blocks + + (Contributed by Eddie Elizondo in :gh:`84436`.) + Porting to Python 3.12 ---------------------- @@ -1293,8 +1311,7 @@ Removed * :c:func:`!PyUnicode_GetSize` * :c:func:`!PyUnicode_GET_DATA_SIZE` -* Remove the ``PyUnicode_InternImmortal()`` function and the - ``SSTATE_INTERNED_IMMORTAL`` macro. +* Remove the ``PyUnicode_InternImmortal()`` function macro. (Contributed by Victor Stinner in :gh:`85858`.) * Remove ``Jython`` compatibility hacks from several stdlib modules and tests. diff --git a/Include/boolobject.h b/Include/boolobject.h index ca21fbfad8e8..976fa35201d0 100644 --- a/Include/boolobject.h +++ b/Include/boolobject.h @@ -11,8 +11,7 @@ PyAPI_DATA(PyTypeObject) PyBool_Type; #define PyBool_Check(x) Py_IS_TYPE((x), &PyBool_Type) -/* Py_False and Py_True are the only two bools in existence. -Don't forget to apply Py_INCREF() when returning either!!! */ +/* Py_False and Py_True are the only two bools in existence. */ /* Don't use these directly */ PyAPI_DATA(PyLongObject) _Py_FalseStruct; @@ -31,8 +30,8 @@ PyAPI_FUNC(int) Py_IsFalse(PyObject *x); #define Py_IsFalse(x) Py_Is((x), Py_False) /* Macros for returning Py_True or Py_False, respectively */ -#define Py_RETURN_TRUE return Py_NewRef(Py_True) -#define Py_RETURN_FALSE return Py_NewRef(Py_False) +#define Py_RETURN_TRUE return Py_True +#define Py_RETURN_FALSE return Py_False /* Function to return a bool from a C long */ PyAPI_FUNC(PyObject *) PyBool_FromLong(long); diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h index 75a74ffa2f9d..3394726dfffd 100644 --- a/Include/cpython/unicodeobject.h +++ b/Include/cpython/unicodeobject.h @@ -98,9 +98,16 @@ typedef struct { Py_ssize_t length; /* Number of code points in the string */ Py_hash_t hash; /* Hash value; -1 if not set */ struct { - /* If interned is set, the two references from the - dictionary to this object are *not* counted in ob_refcnt. */ - unsigned int interned:1; + /* If interned is non-zero, the two references from the + dictionary to this object are *not* counted in ob_refcnt. + The possible values here are: + 0: Not Interned + 1: Interned + 2: Interned and Immortal + 3: Interned, Immortal, and Static + This categorization allows the runtime to determine the right + cleanup mechanism at runtime shutdown. */ + unsigned int interned:2; /* Character size: - PyUnicode_1BYTE_KIND (1): @@ -135,7 +142,7 @@ typedef struct { unsigned int ascii:1; /* Padding to ensure that PyUnicode_DATA() is always aligned to 4 bytes (see issue #19537 on m68k). */ - unsigned int :26; + unsigned int :25; } state; } PyASCIIObject; @@ -183,6 +190,8 @@ PyAPI_FUNC(int) _PyUnicode_CheckConsistency( /* Interning state. */ #define SSTATE_NOT_INTERNED 0 #define SSTATE_INTERNED_MORTAL 1 +#define SSTATE_INTERNED_IMMORTAL 2 +#define SSTATE_INTERNED_IMMORTAL_STATIC 3 /* Use only if you know it's a string */ static inline unsigned int PyUnicode_CHECK_INTERNED(PyObject *op) { diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 14dfd9ea5823..fdfa80bd7d42 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -8,15 +8,13 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#include "pycore_object.h" // _PyObject_IMMORTAL_REFCNT - #ifdef Py_DEBUG static inline void _PyStaticObject_CheckRefcnt(PyObject *obj) { - if (Py_REFCNT(obj) < _PyObject_IMMORTAL_REFCNT) { + if (Py_REFCNT(obj) < _Py_IMMORTAL_REFCNT) { _PyObject_ASSERT_FAILED_MSG(obj, "immortal object has less refcnt than expected " - "_PyObject_IMMORTAL_REFCNT"); + "_Py_IMMORTAL_REFCNT"); } } #endif diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 137a0465d5ec..fe86581e81f6 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -245,7 +245,7 @@ _PyLong_FlipSign(PyLongObject *op) { #define _PyLong_DIGIT_INIT(val) \ { \ - .ob_base = _PyObject_IMMORTAL_INIT(&PyLong_Type), \ + .ob_base = _PyObject_HEAD_INIT(&PyLong_Type) \ .long_value = { \ .lv_tag = TAG_FROM_SIGN_AND_SIZE( \ (val) == 0 ? 0 : ((val) < 0 ? -1 : 1), \ diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index b3d496ed6fc2..2ca047846e09 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -14,21 +14,25 @@ extern "C" { #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_runtime.h" // _PyRuntime -/* This value provides *effective* immortality, meaning the object should never - be deallocated (until runtime finalization). See PEP 683 for more details about - immortality, as well as a proposed mechanism for proper immortality. */ -#define _PyObject_IMMORTAL_REFCNT 999999999 - -#define _PyObject_IMMORTAL_INIT(type) \ - { \ - .ob_refcnt = _PyObject_IMMORTAL_REFCNT, \ - .ob_type = (type), \ - } -#define _PyVarObject_IMMORTAL_INIT(type, size) \ - { \ - .ob_base = _PyObject_IMMORTAL_INIT(type), \ - .ob_size = size, \ - } +/* We need to maintain an internal copy of Py{Var}Object_HEAD_INIT to avoid + designated initializer conflicts in C++20. If we use the deinition in + object.h, we will be mixing designated and non-designated initializers in + pycore objects which is forbiddent in C++20. However, if we then use + designated initializers in object.h then Extensions without designated break. + Furthermore, we can't use designated initializers in Extensions since these + are not supported pre-C++20. Thus, keeping an internal copy here is the most + backwards compatible solution */ +#define _PyObject_HEAD_INIT(type) \ + { \ + _PyObject_EXTRA_INIT \ + .ob_refcnt = _Py_IMMORTAL_REFCNT, \ + .ob_type = (type) \ + }, +#define _PyVarObject_HEAD_INIT(type, size) \ + { \ + .ob_base = _PyObject_HEAD_INIT(type) \ + .ob_size = size \ + }, PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalRefcountErrorFunc( const char *func, @@ -61,9 +65,20 @@ static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n) } #define _Py_RefcntAdd(op, n) _Py_RefcntAdd(_PyObject_CAST(op), n) +static inline void _Py_SetImmortal(PyObject *op) +{ + if (op) { + op->ob_refcnt = _Py_IMMORTAL_REFCNT; + } +} +#define _Py_SetImmortal(op) _Py_SetImmortal(_PyObject_CAST(op)) + static inline void _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct) { + if (_Py_IsImmortal(op)) { + return; + } _Py_DECREF_STAT_INC(); #ifdef Py_REF_DEBUG _Py_DEC_REFTOTAL(_PyInterpreterState_GET()); @@ -82,6 +97,9 @@ _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct) static inline void _Py_DECREF_NO_DEALLOC(PyObject *op) { + if (_Py_IsImmortal(op)) { + return; + } _Py_DECREF_STAT_INC(); #ifdef Py_REF_DEBUG _Py_DEC_REFTOTAL(_PyInterpreterState_GET()); diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index 5b09a45e41cd..d8425b3199a8 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -76,13 +76,13 @@ extern PyTypeObject _PyExc_MemoryError; .latin1 = _Py_str_latin1_INIT, \ }, \ .tuple_empty = { \ - .ob_base = _PyVarObject_IMMORTAL_INIT(&PyTuple_Type, 0) \ + .ob_base = _PyVarObject_HEAD_INIT(&PyTuple_Type, 0) \ }, \ .hamt_bitmap_node_empty = { \ - .ob_base = _PyVarObject_IMMORTAL_INIT(&_PyHamt_BitmapNode_Type, 0) \ + .ob_base = _PyVarObject_HEAD_INIT(&_PyHamt_BitmapNode_Type, 0) \ }, \ .context_token_missing = { \ - .ob_base = _PyObject_IMMORTAL_INIT(&_PyContextTokenMissing_Type), \ + .ob_base = _PyObject_HEAD_INIT(&_PyContextTokenMissing_Type) \ }, \ }, \ }, \ @@ -116,11 +116,11 @@ extern PyTypeObject _PyExc_MemoryError; .singletons = { \ ._not_used = 1, \ .hamt_empty = { \ - .ob_base = _PyObject_IMMORTAL_INIT(&_PyHamt_Type), \ + .ob_base = _PyObject_HEAD_INIT(&_PyHamt_Type) \ .h_root = (PyHamtNode*)&_Py_SINGLETON(hamt_bitmap_node_empty), \ }, \ .last_resort_memory_error = { \ - _PyObject_IMMORTAL_INIT(&_PyExc_MemoryError), \ + _PyObject_HEAD_INIT(&_PyExc_MemoryError) \ }, \ }, \ }, \ @@ -138,7 +138,7 @@ extern PyTypeObject _PyExc_MemoryError; #define _PyBytes_SIMPLE_INIT(CH, LEN) \ { \ - _PyVarObject_IMMORTAL_INIT(&PyBytes_Type, (LEN)), \ + _PyVarObject_HEAD_INIT(&PyBytes_Type, (LEN)) \ .ob_shash = -1, \ .ob_sval = { (CH) }, \ } @@ -149,7 +149,7 @@ extern PyTypeObject _PyExc_MemoryError; #define _PyUnicode_ASCII_BASE_INIT(LITERAL, ASCII) \ { \ - .ob_base = _PyObject_IMMORTAL_INIT(&PyUnicode_Type), \ + .ob_base = _PyObject_HEAD_INIT(&PyUnicode_Type) \ .length = sizeof(LITERAL) - 1, \ .hash = -1, \ .state = { \ diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h index ff97b9a623d2..1bb0f366e781 100644 --- a/Include/internal/pycore_unicodeobject.h +++ b/Include/internal/pycore_unicodeobject.h @@ -12,6 +12,7 @@ extern "C" { #include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI void _PyUnicode_ExactDealloc(PyObject *op); +Py_ssize_t _PyUnicode_InternedSize(void); /* runtime lifecycle */ diff --git a/Include/object.h b/Include/object.h index 2943a6066818..66c3df0d7f78 100644 --- a/Include/object.h +++ b/Include/object.h @@ -78,12 +78,76 @@ whose size is determined when the object is allocated. /* PyObject_HEAD defines the initial segment of every PyObject. */ #define PyObject_HEAD PyObject ob_base; -#define PyObject_HEAD_INIT(type) \ - { _PyObject_EXTRA_INIT \ - 1, (type) }, +/* +Immortalization: + +The following indicates the immortalization strategy depending on the amount +of available bits in the reference count field. All strategies are backwards +compatible but the specific reference count value or immortalization check +might change depending on the specializations for the underlying system. + +Proper deallocation of immortal instances requires distinguishing between +statically allocated immortal instances vs those promoted by the runtime to be +immortal. The latter should be the only instances that require +cleanup during runtime finalization. +*/ + +#if SIZEOF_VOID_P > 4 +/* +In 64+ bit systems, an object will be marked as immortal by setting all of the +lower 32 bits of the reference count field, which is equal to: 0xFFFFFFFF + +Using the lower 32 bits makes the value backwards compatible by allowing +C-Extensions without the updated checks in Py_INCREF and Py_DECREF to safely +increase and decrease the objects reference count. The object would lose its +immortality, but the execution would still be correct. + +Reference count increases will use saturated arithmetic, taking advantage of +having all the lower 32 bits set, which will avoid the reference count to go +beyond the refcount limit. Immortality checks for reference count decreases will +be done by checking the bit sign flag in the lower 32 bits. +*/ +#define _Py_IMMORTAL_REFCNT UINT_MAX + +#else +/* +In 32 bit systems, an object will be marked as immortal by setting all of the +lower 30 bits of the reference count field, which is equal to: 0x3FFFFFFF -#define PyVarObject_HEAD_INIT(type, size) \ - { PyObject_HEAD_INIT(type) (size) }, +Using the lower 30 bits makes the value backwards compatible by allowing +C-Extensions without the updated checks in Py_INCREF and Py_DECREF to safely +increase and decrease the objects reference count. The object would lose its +immortality, but the execution would still be correct. + +Reference count increases and decreases will first go through an immortality +check by comparing the reference count field to the immortality reference count. +*/ +#define _Py_IMMORTAL_REFCNT (UINT_MAX >> 2) +#endif + +// Make all internal uses of PyObject_HEAD_INIT immortal while preserving the +// C-API expectation that the refcnt will be set to 1. +#ifdef Py_BUILD_CORE +#define PyObject_HEAD_INIT(type) \ + { \ + _PyObject_EXTRA_INIT \ + { _Py_IMMORTAL_REFCNT }, \ + (type) \ + }, +#else +#define PyObject_HEAD_INIT(type) \ + { \ + _PyObject_EXTRA_INIT \ + { 1 }, \ + (type) \ + }, +#endif /* Py_BUILD_CORE */ + +#define PyVarObject_HEAD_INIT(type, size) \ + { \ + PyObject_HEAD_INIT(type) \ + (size) \ + }, /* PyObject_VAR_HEAD defines the initial segment of all variable-size * container objects. These end with a declaration of an array with 1 @@ -101,7 +165,12 @@ whose size is determined when the object is allocated. */ struct _object { _PyObject_HEAD_EXTRA - Py_ssize_t ob_refcnt; + union { + Py_ssize_t ob_refcnt; +#if SIZEOF_VOID_P > 4 + PY_UINT32_T ob_refcnt_split[2]; +#endif + }; PyTypeObject *ob_type; }; @@ -152,6 +221,15 @@ static inline Py_ssize_t Py_SIZE(PyObject *ob) { # define Py_SIZE(ob) Py_SIZE(_PyObject_CAST(ob)) #endif +static inline Py_ALWAYS_INLINE int _Py_IsImmortal(PyObject *op) +{ +#if SIZEOF_VOID_P > 4 + return _Py_CAST(PY_INT32_T, op->ob_refcnt) < 0; +#else + return op->ob_refcnt == _Py_IMMORTAL_REFCNT; +#endif +} +#define _Py_IsImmortal(op) _Py_IsImmortal(_PyObject_CAST(op)) static inline int Py_IS_TYPE(PyObject *ob, PyTypeObject *type) { return Py_TYPE(ob) == type; @@ -162,6 +240,13 @@ static inline int Py_IS_TYPE(PyObject *ob, PyTypeObject *type) { static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) { + // This immortal check is for code that is unaware of immortal objects. + // The runtime tracks these objects and we should avoid as much + // as possible having extensions inadvertently change the refcnt + // of an immortalized object. + if (_Py_IsImmortal(ob)) { + return; + } ob->ob_refcnt = refcnt; } #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 @@ -524,19 +609,33 @@ PyAPI_FUNC(void) Py_DecRef(PyObject *); PyAPI_FUNC(void) _Py_IncRef(PyObject *); PyAPI_FUNC(void) _Py_DecRef(PyObject *); -static inline void Py_INCREF(PyObject *op) +static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op) { #if defined(Py_REF_DEBUG) && defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030A0000 // Stable ABI for Python 3.10 built in debug mode. _Py_IncRef(op); #else - _Py_INCREF_STAT_INC(); // Non-limited C API and limited C API for Python 3.9 and older access // directly PyObject.ob_refcnt. +#if SIZEOF_VOID_P > 4 + // Portable saturated add, branching on the carry flag and set low bits + PY_UINT32_T cur_refcnt = op->ob_refcnt_split[PY_BIG_ENDIAN]; + PY_UINT32_T new_refcnt = cur_refcnt + 1; + if (new_refcnt == 0) { + return; + } + op->ob_refcnt_split[PY_BIG_ENDIAN] = new_refcnt; +#else + // Explicitly check immortality against the immortal value + if (_Py_IsImmortal(op)) { + return; + } + op->ob_refcnt++; +#endif + _Py_INCREF_STAT_INC(); #ifdef Py_REF_DEBUG _Py_INC_REFTOTAL(); -#endif // Py_REF_DEBUG - op->ob_refcnt++; +#endif #endif } #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 @@ -553,6 +652,9 @@ static inline void Py_DECREF(PyObject *op) { #elif defined(Py_REF_DEBUG) static inline void Py_DECREF(const char *filename, int lineno, PyObject *op) { + if (_Py_IsImmortal(op)) { + return; + } _Py_DECREF_STAT_INC(); _Py_DEC_REFTOTAL(); if (--op->ob_refcnt != 0) { @@ -567,11 +669,14 @@ static inline void Py_DECREF(const char *filename, int lineno, PyObject *op) #define Py_DECREF(op) Py_DECREF(__FILE__, __LINE__, _PyObject_CAST(op)) #else -static inline void Py_DECREF(PyObject *op) +static inline Py_ALWAYS_INLINE void Py_DECREF(PyObject *op) { - _Py_DECREF_STAT_INC(); // Non-limited C API and limited C API for Python 3.9 and older access // directly PyObject.ob_refcnt. + if (_Py_IsImmortal(op)) { + return; + } + _Py_DECREF_STAT_INC(); if (--op->ob_refcnt == 0) { _Py_Dealloc(op); } @@ -721,7 +826,7 @@ PyAPI_FUNC(int) Py_IsNone(PyObject *x); #define Py_IsNone(x) Py_Is((x), Py_None) /* Macro for returning Py_None from a function */ -#define Py_RETURN_NONE return Py_NewRef(Py_None) +#define Py_RETURN_NONE return Py_None /* Py_NotImplemented is a singleton used to signal that an operation is @@ -731,7 +836,7 @@ PyAPI_DATA(PyObject) _Py_NotImplementedStruct; /* Don't use this directly */ #define Py_NotImplemented (&_Py_NotImplementedStruct) /* Macro for returning Py_NotImplemented from a function */ -#define Py_RETURN_NOTIMPLEMENTED return Py_NewRef(Py_NotImplemented) +#define Py_RETURN_NOTIMPLEMENTED return Py_NotImplemented /* Rich comparison opcodes */ #define Py_LT 0 diff --git a/Include/pyport.h b/Include/pyport.h index eef0fe1bfd71..5e226f5cb467 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -184,7 +184,6 @@ typedef Py_ssize_t Py_ssize_clean_t; # define Py_LOCAL_INLINE(type) static inline type #endif -// bpo-28126: Py_MEMCPY is kept for backwards compatibility, #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 # define Py_MEMCPY memcpy #endif diff --git a/Lib/test/_test_embed_structseq.py b/Lib/test/_test_embed_structseq.py index 868f9f83e8be..834daa4df55f 100644 --- a/Lib/test/_test_embed_structseq.py +++ b/Lib/test/_test_embed_structseq.py @@ -1,27 +1,31 @@ import sys import types -import unittest +# Note: This test file can't import `unittest` since the runtime can't +# currently guarantee that it will not leak memory. Doing so will mark +# the test as passing but with reference leaks. This can safely import +# the `unittest` library once there's a strict guarantee of no leaks +# during runtime shutdown. # bpo-46417: Test that structseq types used by the sys module are still # valid when Py_Finalize()/Py_Initialize() are called multiple times. -class TestStructSeq(unittest.TestCase): +class TestStructSeq: # test PyTypeObject members - def check_structseq(self, obj_type): + def _check_structseq(self, obj_type): # ob_refcnt - self.assertGreaterEqual(sys.getrefcount(obj_type), 1) + assert sys.getrefcount(obj_type) > 1 # tp_base - self.assertTrue(issubclass(obj_type, tuple)) + assert issubclass(obj_type, tuple) # tp_bases - self.assertEqual(obj_type.__bases__, (tuple,)) + assert obj_type.__bases__ == (tuple,) # tp_dict - self.assertIsInstance(obj_type.__dict__, types.MappingProxyType) + assert isinstance(obj_type.__dict__, types.MappingProxyType) # tp_mro - self.assertEqual(obj_type.__mro__, (obj_type, tuple, object)) + assert obj_type.__mro__ == (obj_type, tuple, object) # tp_name - self.assertIsInstance(type.__name__, str) + assert isinstance(type.__name__, str) # tp_subclasses - self.assertEqual(obj_type.__subclasses__(), []) + assert obj_type.__subclasses__() == [] def test_sys_attrs(self): for attr_name in ( @@ -32,23 +36,23 @@ def test_sys_attrs(self): 'thread_info', # ThreadInfoType 'version_info', # VersionInfoType ): - with self.subTest(attr=attr_name): - attr = getattr(sys, attr_name) - self.check_structseq(type(attr)) + attr = getattr(sys, attr_name) + self._check_structseq(type(attr)) def test_sys_funcs(self): func_names = ['get_asyncgen_hooks'] # AsyncGenHooksType if hasattr(sys, 'getwindowsversion'): func_names.append('getwindowsversion') # WindowsVersionType for func_name in func_names: - with self.subTest(func=func_name): - func = getattr(sys, func_name) - obj = func() - self.check_structseq(type(obj)) + func = getattr(sys, func_name) + obj = func() + self._check_structseq(type(obj)) try: - unittest.main() + tests = TestStructSeq() + tests.test_sys_attrs() + tests.test_sys_funcs() except SystemExit as exc: if exc.args[0] != 0: raise diff --git a/Lib/test/libregrtest/refleak.py b/Lib/test/libregrtest/refleak.py index 4298fa806e10..2de8c6cfbc61 100644 --- a/Lib/test/libregrtest/refleak.py +++ b/Lib/test/libregrtest/refleak.py @@ -73,9 +73,10 @@ def get_pooled_int(value): fd_deltas = [0] * repcount getallocatedblocks = sys.getallocatedblocks gettotalrefcount = sys.gettotalrefcount + getunicodeinternedsize = sys.getunicodeinternedsize fd_count = os_helper.fd_count # initialize variables to make pyflakes quiet - rc_before = alloc_before = fd_before = 0 + rc_before = alloc_before = fd_before = interned_before = 0 if not ns.quiet: print("beginning", repcount, "repetitions", file=sys.stderr) @@ -91,9 +92,13 @@ def get_pooled_int(value): dash_R_cleanup(fs, ps, pic, zdc, abcs) support.gc_collect() - # Read memory statistics immediately after the garbage collection - alloc_after = getallocatedblocks() - rc_after = gettotalrefcount() + # Read memory statistics immediately after the garbage collection. + # Also, readjust the reference counts and alloc blocks by ignoring + # any strings that might have been interned during test_func. These + # strings will be deallocated at runtime shutdown + interned_after = getunicodeinternedsize() + alloc_after = getallocatedblocks() - interned_after + rc_after = gettotalrefcount() - interned_after * 2 fd_after = fd_count() if not ns.quiet: @@ -106,6 +111,7 @@ def get_pooled_int(value): alloc_before = alloc_after rc_before = rc_after fd_before = fd_after + interned_before = interned_after if not ns.quiet: print(file=sys.stderr) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index e7a79bc13b7f..04dd8ff3070c 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -28,7 +28,7 @@ from types import AsyncGeneratorType, FunctionType, CellType from operator import neg from test import support -from test.support import (swap_attr, maybe_get_event_loop_policy) +from test.support import (cpython_only, swap_attr, maybe_get_event_loop_policy) from test.support.os_helper import (EnvironmentVarGuard, TESTFN, unlink) from test.support.script_helper import assert_python_ok from test.support.warnings_helper import check_warnings @@ -2370,6 +2370,28 @@ def __del__(self): self.assertEqual(["before", "after"], out.decode().splitlines()) + at cpython_only +class ImmortalTests(unittest.TestCase): + def test_immortal(self): + none_refcount = sys.getrefcount(None) + true_refcount = sys.getrefcount(True) + false_refcount = sys.getrefcount(False) + smallint_refcount = sys.getrefcount(100) + + # Assert that all of these immortal instances have large ref counts. + self.assertGreater(none_refcount, 2 ** 15) + self.assertGreater(true_refcount, 2 ** 15) + self.assertGreater(false_refcount, 2 ** 15) + self.assertGreater(smallint_refcount, 2 ** 15) + + # Confirm that the refcount doesn't change even with a new ref to them. + l = [None, True, False, 100] + self.assertEqual(sys.getrefcount(None), none_refcount) + self.assertEqual(sys.getrefcount(True), true_refcount) + self.assertEqual(sys.getrefcount(False), false_refcount) + self.assertEqual(sys.getrefcount(100), smallint_refcount) + + class TestType(unittest.TestCase): def test_new_type(self): A = type('A', (), {}) diff --git a/Lib/test/test_ctypes/test_python_api.py b/Lib/test/test_ctypes/test_python_api.py index 49571f97bbe1..de8989e2c330 100644 --- a/Lib/test/test_ctypes/test_python_api.py +++ b/Lib/test/test_ctypes/test_python_api.py @@ -46,7 +46,8 @@ def test_PyLong_Long(self): pythonapi.PyLong_AsLong.restype = c_long res = pythonapi.PyLong_AsLong(42) - self.assertEqual(grc(res), ref42 + 1) + # Small int refcnts don't change + self.assertEqual(grc(res), ref42) del res self.assertEqual(grc(42), ref42) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 1aebe1b111f2..611cd27ecf12 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -385,7 +385,8 @@ def test_refcount(self): self.assertRaises(TypeError, sys.getrefcount) c = sys.getrefcount(None) n = None - self.assertEqual(sys.getrefcount(None), c+1) + # Singleton refcnts don't change + self.assertEqual(sys.getrefcount(None), c) del n self.assertEqual(sys.getrefcount(None), c) if hasattr(sys, "gettotalrefcount"): diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index 333b97688af5..95944c7c7116 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -600,9 +600,15 @@ def test_zippath_from_non_installed_posix(self): ld_library_path_env = "DYLD_LIBRARY_PATH" else: ld_library_path_env = "LD_LIBRARY_PATH" - subprocess.check_call(cmd, - env={"PYTHONPATH": pythonpath, - ld_library_path_env: ld_library_path}) + # Note that in address sanitizer mode, the current runtime + # implementation leaks memory due to not being able to correctly + # clean all unicode objects during runtime shutdown. Therefore, + # this uses subprocess.run instead of subprocess.check_call to + # maintain the core of the test while not failing due to the refleaks. + # This should be able to use check_call once all refleaks are fixed. + subprocess.run(cmd, + env={"PYTHONPATH": pythonpath, + ld_library_path_env: ld_library_path}) envpy = os.path.join(self.env_dir, self.bindir, self.exe) # Now check the venv created from the non-installed python has # correct zip path in pythonpath. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-02-22-14-57.gh-issue-84436.hvMgwF.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-02-22-14-57.gh-issue-84436.hvMgwF.rst new file mode 100644 index 000000000000..c4d8ce75b35a --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-02-22-14-57.gh-issue-84436.hvMgwF.rst @@ -0,0 +1,3 @@ +The implementation of PEP-683 which adds Immortal Objects by using a fixed +reference count that skips reference counting to make objects truly +immutable. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 4eaa5490b613..1d00fc3e7177 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -418,8 +418,20 @@ validate_list(PyGC_Head *head, enum flagstates flags) static void update_refs(PyGC_Head *containers) { + PyGC_Head *next; PyGC_Head *gc = GC_NEXT(containers); - for (; gc != containers; gc = GC_NEXT(gc)) { + + while (gc != containers) { + next = GC_NEXT(gc); + /* Move any object that might have become immortal to the + * permanent generation as the reference count is not accurately + * reflecting the actual number of live references to this object + */ + if (_Py_IsImmortal(FROM_GC(gc))) { + gc_list_move(gc, &get_gc_state()->permanent_generation.head); + gc = next; + continue; + } gc_reset_refs(gc, Py_REFCNT(FROM_GC(gc))); /* Python's cyclic gc should never see an incoming refcount * of 0: if something decref'ed to 0, it should have been @@ -440,6 +452,7 @@ update_refs(PyGC_Head *containers) * check instead of an assert? */ _PyObject_ASSERT(FROM_GC(gc), gc_get_refs(gc) != 0); + gc = next; } } diff --git a/Objects/boolobject.c b/Objects/boolobject.c index 9d8e956e06f7..597a76fa5cb1 100644 --- a/Objects/boolobject.c +++ b/Objects/boolobject.c @@ -145,10 +145,14 @@ static PyNumberMethods bool_as_number = { 0, /* nb_index */ }; -static void _Py_NO_RETURN -bool_dealloc(PyObject* Py_UNUSED(ignore)) +static void +bool_dealloc(PyObject *boolean) { - _Py_FatalRefcountError("deallocating True or False"); + /* This should never get called, but we also don't want to SEGV if + * we accidentally decref Booleans out of existence. Instead, + * since bools are immortal, re-set the reference count. + */ + _Py_SetImmortal(boolean); } /* The type object for bool. Note that this cannot be subclassed! */ diff --git a/Objects/bytes_methods.c b/Objects/bytes_methods.c index ef9e65e566ec..33aa9c3db6e8 100644 --- a/Objects/bytes_methods.c +++ b/Objects/bytes_methods.c @@ -258,9 +258,12 @@ _Py_bytes_istitle(const char *cptr, Py_ssize_t len) const unsigned char *e; int cased, previous_is_cased; - /* Shortcut for single character strings */ - if (len == 1) - return PyBool_FromLong(Py_ISUPPER(*p)); + if (len == 1) { + if (Py_ISUPPER(*p)) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; + } /* Special case for empty strings */ if (len == 0) diff --git a/Objects/longobject.c b/Objects/longobject.c index bb4eac0d932b..d98bbbb6d6ff 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -52,8 +52,7 @@ static PyObject * get_small_int(sdigit ival) { assert(IS_SMALL_INT(ival)); - PyObject *v = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + ival]; - return Py_NewRef(v); + return (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + ival]; } static PyLongObject * @@ -3271,6 +3270,27 @@ long_richcompare(PyObject *self, PyObject *other, int op) Py_RETURN_RICHCOMPARE(result, 0, op); } +static void +long_dealloc(PyObject *self) +{ + /* This should never get called, but we also don't want to SEGV if + * we accidentally decref small Ints out of existence. Instead, + * since small Ints are immortal, re-set the reference count. + */ + PyLongObject *pylong = (PyLongObject*)self; + if (pylong && _PyLong_IsCompact(pylong)) { + stwodigits ival = medium_value(pylong); + if (IS_SMALL_INT(ival)) { + PyLongObject *small_pylong = (PyLongObject *)get_small_int((sdigit)ival); + if (pylong == small_pylong) { + _Py_SetImmortal(self); + return; + } + } + } + Py_TYPE(self)->tp_free(self); +} + static Py_hash_t long_hash(PyLongObject *v) { @@ -6233,7 +6253,7 @@ PyTypeObject PyLong_Type = { "int", /* tp_name */ offsetof(PyLongObject, long_value.ob_digit), /* tp_basicsize */ sizeof(digit), /* tp_itemsize */ - 0, /* tp_dealloc */ + long_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ diff --git a/Objects/object.c b/Objects/object.c index e26f737fccd6..e508881c67d2 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1754,10 +1754,14 @@ none_repr(PyObject *op) return PyUnicode_FromString("None"); } -static void _Py_NO_RETURN -none_dealloc(PyObject* Py_UNUSED(ignore)) +static void +none_dealloc(PyObject* none) { - _Py_FatalRefcountError("deallocating None"); + /* This should never get called, but we also don't want to SEGV if + * we accidentally decref None out of existence. Instead, + * since None is an immortal object, re-set the reference count. + */ + _Py_SetImmortal(none); } static PyObject * @@ -1823,7 +1827,7 @@ PyTypeObject _PyNone_Type = { "NoneType", 0, 0, - none_dealloc, /*tp_dealloc*/ /*never called*/ + none_dealloc, /*tp_dealloc*/ 0, /*tp_vectorcall_offset*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ @@ -1860,8 +1864,9 @@ PyTypeObject _PyNone_Type = { }; PyObject _Py_NoneStruct = { - _PyObject_EXTRA_INIT - 1, &_PyNone_Type + _PyObject_EXTRA_INIT + { _Py_IMMORTAL_REFCNT }, + &_PyNone_Type }; /* NotImplemented is an object that can be used to signal that an @@ -1894,13 +1899,14 @@ notimplemented_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) Py_RETURN_NOTIMPLEMENTED; } -static void _Py_NO_RETURN -notimplemented_dealloc(PyObject* ignore) +static void +notimplemented_dealloc(PyObject *notimplemented) { /* This should never get called, but we also don't want to SEGV if - * we accidentally decref NotImplemented out of existence. + * we accidentally decref NotImplemented out of existence. Instead, + * since Notimplemented is an immortal object, re-set the reference count. */ - Py_FatalError("deallocating NotImplemented"); + _Py_SetImmortal(notimplemented); } static int @@ -1962,7 +1968,8 @@ PyTypeObject _PyNotImplemented_Type = { PyObject _Py_NotImplementedStruct = { _PyObject_EXTRA_INIT - 1, &_PyNotImplemented_Type + { _Py_IMMORTAL_REFCNT }, + &_PyNotImplemented_Type }; extern PyTypeObject _Py_GenericAliasIterType; @@ -2143,7 +2150,8 @@ new_reference(PyObject *op) if (_PyRuntime.tracemalloc.config.tracing) { _PyTraceMalloc_NewReference(op); } - Py_SET_REFCNT(op, 1); + // Skip the immortal object check in Py_SET_REFCNT; always set refcnt to 1 + op->ob_refcnt = 1; #ifdef Py_TRACE_REFS _Py_AddToAllObjects(op, 1); #endif diff --git a/Objects/setobject.c b/Objects/setobject.c index fcdda2a0bca2..58f0ae73c0c4 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -2543,6 +2543,7 @@ static PyTypeObject _PySetDummy_Type = { }; static PyObject _dummy_struct = { - _PyObject_EXTRA_INIT - 2, &_PySetDummy_Type + _PyObject_EXTRA_INIT + { _Py_IMMORTAL_REFCNT }, + &_PySetDummy_Type }; diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index 584ebce721fa..e6776ac92b66 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -29,6 +29,16 @@ ellipsis_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) return Py_NewRef(Py_Ellipsis); } +static void +ellipsis_dealloc(PyObject *ellipsis) +{ + /* This should never get called, but we also don't want to SEGV if + * we accidentally decref Ellipsis out of existence. Instead, + * since Ellipsis is an immortal object, re-set the reference count. + */ + _Py_SetImmortal(ellipsis); +} + static PyObject * ellipsis_repr(PyObject *op) { @@ -51,7 +61,7 @@ PyTypeObject PyEllipsis_Type = { "ellipsis", /* tp_name */ 0, /* tp_basicsize */ 0, /* tp_itemsize */ - 0, /*never called*/ /* tp_dealloc */ + ellipsis_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -89,7 +99,8 @@ PyTypeObject PyEllipsis_Type = { PyObject _Py_EllipsisObject = { _PyObject_EXTRA_INIT - 1, &PyEllipsis_Type + { _Py_IMMORTAL_REFCNT }, + &PyEllipsis_Type }; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 9ea458f30394..85bcd05d5a29 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -318,27 +318,11 @@ _PyType_InitCache(PyInterpreterState *interp) entry->version = 0; // Set to None so _PyType_Lookup() can use Py_SETREF(), // rather than using slower Py_XSETREF(). - // (See _PyType_FixCacheRefcounts() about the refcount.) entry->name = Py_None; entry->value = NULL; } } -// This is the temporary fix used by pycore_create_interpreter(), -// in pylifecycle.c. _PyType_InitCache() is called before the GIL -// has been created (for the main interpreter) and without the -// "current" thread state set. This causes crashes when the -// reftotal is updated, so we don't modify the refcount in -// _PyType_InitCache(), and instead do it later by calling -// _PyType_FixCacheRefcounts(). -// XXX This workaround should be removed once we have immortal -// objects (PEP 683). -void -_PyType_FixCacheRefcounts(void) -{ - _Py_RefcntAdd(Py_None, (1 << MCACHE_SIZE_EXP)); -} - static unsigned int _PyType_ClearCache(PyInterpreterState *interp) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 85e5ae735709..fd056e38f3f8 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -228,14 +228,18 @@ static inline PyObject* unicode_new_empty(void) to strings in this dictionary are *not* counted in the string's ob_refcnt. When the interned string reaches a refcnt of 0 the string deallocation function will delete the reference from this dictionary. - Another way to look at this is that to say that the actual reference - count of a string is: s->ob_refcnt + (s->state ? 2 : 0) */ static inline PyObject *get_interned_dict(PyInterpreterState *interp) { return _Py_INTERP_CACHED_OBJECT(interp, interned_strings); } +Py_ssize_t +_PyUnicode_InternedSize() +{ + return PyObject_Length(get_interned_dict(_PyInterpreterState_GET())); +} + static int init_interned_dict(PyInterpreterState *interp) { @@ -1538,30 +1542,19 @@ find_maxchar_surrogates(const wchar_t *begin, const wchar_t *end, static void unicode_dealloc(PyObject *unicode) { - PyInterpreterState *interp = _PyInterpreterState_GET(); #ifdef Py_DEBUG if (!unicode_is_finalizing() && unicode_is_singleton(unicode)) { _Py_FatalRefcountError("deallocating an Unicode singleton"); } #endif + /* This should never get called, but we also don't want to SEGV if + * we accidentally decref an immortal string out of existence. Since + * the string is an immortal object, just re-set the reference count. + */ if (PyUnicode_CHECK_INTERNED(unicode)) { - /* Revive the dead object temporarily. PyDict_DelItem() removes two - references (key and value) which were ignored by - PyUnicode_InternInPlace(). Use refcnt=3 rather than refcnt=2 - to prevent calling unicode_dealloc() again. Adjust refcnt after - PyDict_DelItem(). */ - assert(Py_REFCNT(unicode) == 0); - Py_SET_REFCNT(unicode, 3); - PyObject *interned = get_interned_dict(interp); - assert(interned != NULL); - if (PyDict_DelItem(interned, unicode) != 0) { - _PyErr_WriteUnraisableMsg("deletion of interned string failed", - NULL); - } - assert(Py_REFCNT(unicode) == 1); - Py_SET_REFCNT(unicode, 0); + _Py_SetImmortal(unicode); + return; } - if (_PyUnicode_HAS_UTF8_MEMORY(unicode)) { PyObject_Free(_PyUnicode_UTF8(unicode)); } @@ -14637,11 +14630,21 @@ _PyUnicode_InternInPlace(PyInterpreterState *interp, PyObject **p) return; } - /* The two references in interned dict (key and value) are not counted by - refcnt. unicode_dealloc() and _PyUnicode_ClearInterned() take care of - this. */ - Py_SET_REFCNT(s, Py_REFCNT(s) - 2); - _PyUnicode_STATE(s).interned = 1; + if (_Py_IsImmortal(s)) { + _PyUnicode_STATE(*p).interned = SSTATE_INTERNED_IMMORTAL_STATIC; + return; + } +#ifdef Py_REF_DEBUG + /* The reference count value excluding the 2 references from the + interned dictionary should be excluded from the RefTotal. The + decrements to these objects will not be registered so they + need to be accounted for in here. */ + for (Py_ssize_t i = 0; i < Py_REFCNT(s) - 2; i++) { + _Py_DecRefTotal(_PyInterpreterState_GET()); + } +#endif + _Py_SetImmortal(s); + _PyUnicode_STATE(*p).interned = SSTATE_INTERNED_IMMORTAL; } void @@ -14681,10 +14684,20 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp) } assert(PyDict_CheckExact(interned)); - /* Interned unicode strings are not forcibly deallocated; rather, we give - them their stolen references back, and then clear and DECREF the - interned dict. */ - + /* TODO: + * Currently, the runtime is not able to guarantee that it can exit without + * allocations that carry over to a future initialization of Python within + * the same process. i.e: + * ./python -X showrefcount -c 'import itertools' + * [237 refs, 237 blocks] + * + * Therefore, this should remain disabled for until there is a strict guarantee + * that no memory will be left after `Py_Finalize`. + */ +#ifdef Py_DEBUG + /* For all non-singleton interned strings, restore the two valid references + to that instance from within the intern string dictionary and let the + normal reference counting process clean up these instances. */ #ifdef INTERNED_STATS fprintf(stderr, "releasing %zd interned strings\n", PyDict_GET_SIZE(interned)); @@ -14694,15 +14707,27 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp) Py_ssize_t pos = 0; PyObject *s, *ignored_value; while (PyDict_Next(interned, &pos, &s, &ignored_value)) { - assert(PyUnicode_CHECK_INTERNED(s)); - // Restore the two references (key and value) ignored - // by PyUnicode_InternInPlace(). - Py_SET_REFCNT(s, Py_REFCNT(s) + 2); + assert(PyUnicode_IS_READY(s)); + switch (PyUnicode_CHECK_INTERNED(s)) { + case SSTATE_INTERNED_IMMORTAL: + // Skip the Immortal Instance check and restore + // the two references (key and value) ignored + // by PyUnicode_InternInPlace(). + s->ob_refcnt = 2; #ifdef INTERNED_STATS - total_length += PyUnicode_GET_LENGTH(s); + total_length += PyUnicode_GET_LENGTH(s); #endif - - _PyUnicode_STATE(s).interned = 0; + break; + case SSTATE_INTERNED_IMMORTAL_STATIC: + break; + case SSTATE_INTERNED_MORTAL: + /* fall through */ + case SSTATE_NOT_INTERNED: + /* fall through */ + default: + Py_UNREACHABLE(); + } + _PyUnicode_STATE(s).interned = SSTATE_NOT_INTERNED; } #ifdef INTERNED_STATS fprintf(stderr, @@ -14710,6 +14735,12 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp) total_length); #endif + struct _Py_unicode_state *state = &interp->unicode; + struct _Py_unicode_ids *ids = &state->ids; + for (Py_ssize_t i=0; i < ids->size; i++) { + Py_XINCREF(ids->array[i]); + } +#endif /* Py_DEBUG */ clear_interned_dict(interp); } diff --git a/Programs/_testembed.c b/Programs/_testembed.c index 00717114b402..f78ba41fe7b4 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -1911,14 +1911,13 @@ static int test_unicode_id_init(void) str1 = _PyUnicode_FromId(&PyId_test_unicode_id_init); assert(str1 != NULL); - assert(Py_REFCNT(str1) == 1); + assert(_Py_IsImmortal(str1)); str2 = PyUnicode_FromString("test_unicode_id_init"); assert(str2 != NULL); assert(PyUnicode_Compare(str1, str2) == 0); - // str1 is a borrowed reference Py_DECREF(str2); Py_Finalize(); diff --git a/Python/ceval.c b/Python/ceval.c index d8495da81e94..358835024fd2 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -53,8 +53,11 @@ #undef Py_DECREF #define Py_DECREF(arg) \ do { \ - _Py_DECREF_STAT_INC(); \ PyObject *op = _PyObject_CAST(arg); \ + if (_Py_IsImmortal(op)) { \ + break; \ + } \ + _Py_DECREF_STAT_INC(); \ if (--op->ob_refcnt == 0) { \ destructor dealloc = Py_TYPE(op)->tp_dealloc; \ (*dealloc)(op); \ @@ -77,8 +80,11 @@ #undef _Py_DECREF_SPECIALIZED #define _Py_DECREF_SPECIALIZED(arg, dealloc) \ do { \ - _Py_DECREF_STAT_INC(); \ PyObject *op = _PyObject_CAST(arg); \ + if (_Py_IsImmortal(op)) { \ + break; \ + } \ + _Py_DECREF_STAT_INC(); \ if (--op->ob_refcnt == 0) { \ destructor d = (destructor)(dealloc); \ d(op); \ diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index 46252dd40432..7a7c188bcccc 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -912,6 +912,34 @@ sys_getallocatedblocks(PyObject *module, PyObject *Py_UNUSED(ignored)) return return_value; } +PyDoc_STRVAR(sys_getunicodeinternedsize__doc__, +"getunicodeinternedsize($module, /)\n" +"--\n" +"\n" +"Return the number of elements of the unicode interned dictionary"); + +#define SYS_GETUNICODEINTERNEDSIZE_METHODDEF \ + {"getunicodeinternedsize", (PyCFunction)sys_getunicodeinternedsize, METH_NOARGS, sys_getunicodeinternedsize__doc__}, + +static Py_ssize_t +sys_getunicodeinternedsize_impl(PyObject *module); + +static PyObject * +sys_getunicodeinternedsize(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + Py_ssize_t _return_value; + + _return_value = sys_getunicodeinternedsize_impl(module); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyLong_FromSsize_t(_return_value); + +exit: + return return_value; +} + PyDoc_STRVAR(sys__getframe__doc__, "_getframe($module, depth=0, /)\n" "--\n" @@ -1387,4 +1415,4 @@ sys__getframemodulename(PyObject *module, PyObject *const *args, Py_ssize_t narg #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=5c761f14326ced54 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=6d598acc26237fbe input=a9049054013a1b77]*/ diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 2a3b2b8ebeea..8334f596eb3e 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -16,13 +16,13 @@ static PyObject DISABLE = { - .ob_refcnt = _PyObject_IMMORTAL_REFCNT, + .ob_refcnt = _Py_IMMORTAL_REFCNT, .ob_type = &PyBaseObject_Type }; PyObject _PyInstrumentation_MISSING = { - .ob_refcnt = _PyObject_IMMORTAL_REFCNT, + .ob_refcnt = _Py_IMMORTAL_REFCNT, .ob_type = &PyBaseObject_Type }; diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c index cf345bddda79..e509e63a087a 100644 --- a/Python/legacy_tracing.c +++ b/Python/legacy_tracing.c @@ -324,7 +324,7 @@ sys_trace_exception_handled( PyTypeObject _PyLegacyEventHandler_Type = { - _PyVarObject_IMMORTAL_INIT(&PyType_Type, 0), + PyVarObject_HEAD_INIT(&PyType_Type, 0) "sys.legacy_event_handler", sizeof(_PyLegacyEventHandler), .tp_dealloc = (destructor)PyObject_Free, diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index d6627bc6b7e8..a510c9b22168 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -808,11 +808,6 @@ pycore_interp_init(PyThreadState *tstate) PyStatus status; PyObject *sysmod = NULL; - // This is a temporary fix until we have immortal objects. - // (See _PyType_InitCache() in typeobject.c.) - extern void _PyType_FixCacheRefcounts(void); - _PyType_FixCacheRefcounts(); - // Create singletons before the first PyType_Ready() call, since // PyType_Ready() uses singletons like the Unicode empty string (tp_doc) // and the empty tuple singletons (tp_bases). diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 4d693a1be1f8..1e42e8dfceb5 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1874,6 +1874,18 @@ sys_getallocatedblocks_impl(PyObject *module) return _Py_GetAllocatedBlocks(); } +/*[clinic input] +sys.getunicodeinternedsize -> Py_ssize_t + +Return the number of elements of the unicode interned dictionary +[clinic start generated code]*/ + +static Py_ssize_t +sys_getunicodeinternedsize_impl(PyObject *module) +/*[clinic end generated code: output=ad0e4c9738ed4129 input=726298eaa063347a]*/ +{ + return _PyUnicode_InternedSize(); +} /*[clinic input] sys._getframe @@ -2243,6 +2255,7 @@ static PyMethodDef sys_methods[] = { SYS_GETDEFAULTENCODING_METHODDEF SYS_GETDLOPENFLAGS_METHODDEF SYS_GETALLOCATEDBLOCKS_METHODDEF + SYS_GETUNICODEINTERNEDSIZE_METHODDEF SYS_GETFILESYSTEMENCODING_METHODDEF SYS_GETFILESYSTEMENCODEERRORS_METHODDEF #ifdef Py_TRACE_REFS diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py index aba5fecd8b1a..5cfef5c572c4 100644 --- a/Tools/build/deepfreeze.py +++ b/Tools/build/deepfreeze.py @@ -142,7 +142,7 @@ def block(self, prefix: str, suffix: str = "") -> None: def object_head(self, typename: str) -> None: with self.block(".ob_base =", ","): - self.write(f".ob_refcnt = 999999999,") + self.write(f".ob_refcnt = _Py_IMMORTAL_REFCNT,") self.write(f".ob_type = &{typename},") def object_var_head(self, typename: str, size: int) -> None: From webhook-mailer at python.org Sat Apr 22 17:42:05 2023 From: webhook-mailer at python.org (hugovk) Date: Sat, 22 Apr 2023 21:42:05 -0000 Subject: [Python-checkins] Revert "Avoid error lexing multiprocessing docs code block on Pygments 2.15.0" (#103616) Message-ID: https://github.com/python/cpython/commit/8cb2b0f953288ff8749e686c268097cdd5a393e2 commit: 8cb2b0f953288ff8749e686c268097cdd5a393e2 branch: main author: Hugo van Kemenade committer: hugovk date: 2023-04-22T15:41:58-06:00 summary: Revert "Avoid error lexing multiprocessing docs code block on Pygments 2.15.0" (#103616) This reverts commit ace51dcdb781b0608b1273d246ebaee849561435. files: M Doc/library/multiprocessing.rst diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 84e309f1bc83..8454296b815b 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -452,9 +452,7 @@ process which created it. importable by the children. This is covered in :ref:`multiprocessing-programming` however it is worth pointing out here. This means that some examples, such as the :class:`multiprocessing.pool.Pool` examples will not work in the - interactive interpreter. For example: - - .. code-block:: text + interactive interpreter. For example:: >>> from multiprocessing import Pool >>> p = Pool(5) From webhook-mailer at python.org Sat Apr 22 18:13:29 2023 From: webhook-mailer at python.org (hugovk) Date: Sat, 22 Apr 2023 22:13:29 -0000 Subject: [Python-checkins] [3.11] Revert "Avoid error lexing multiprocessing docs code block on Pygments 2.15.0" (GH-103616) (#103695) Message-ID: https://github.com/python/cpython/commit/050b6b34d055fc034ac86a1cfc8c5c7d3f98b2e5 commit: 050b6b34d055fc034ac86a1cfc8c5c7d3f98b2e5 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: hugovk date: 2023-04-22T16:13:22-06:00 summary: [3.11] Revert "Avoid error lexing multiprocessing docs code block on Pygments 2.15.0" (GH-103616) (#103695) Revert "Avoid error lexing multiprocessing docs code block on Pygments 2.15.0" (GH-103616) This reverts commit ace51dcdb781b0608b1273d246ebaee849561435. (cherry picked from commit 8cb2b0f953288ff8749e686c268097cdd5a393e2) Co-authored-by: Hugo van Kemenade files: M Doc/library/multiprocessing.rst diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 6f0062012b38..b5ceeb796f8f 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -445,9 +445,7 @@ process which created it. importable by the children. This is covered in :ref:`multiprocessing-programming` however it is worth pointing out here. This means that some examples, such as the :class:`multiprocessing.pool.Pool` examples will not work in the - interactive interpreter. For example: - - .. code-block:: text + interactive interpreter. For example:: >>> from multiprocessing import Pool >>> p = Pool(5) From webhook-mailer at python.org Sat Apr 22 19:34:01 2023 From: webhook-mailer at python.org (CAM-Gerlach) Date: Sat, 22 Apr 2023 23:34:01 -0000 Subject: [Python-checkins] gh-68654: Clarify subdirectories used by pkgutil.extend_path (#103701) Message-ID: https://github.com/python/cpython/commit/7bf94568a9a4101c72b8bf555a811028e5b45ced commit: 7bf94568a9a4101c72b8bf555a811028e5b45ced branch: main author: Randy <69558016+san-juan1667 at users.noreply.github.com> committer: CAM-Gerlach date: 2023-04-22T17:33:50-06:00 summary: gh-68654: Clarify subdirectories used by pkgutil.extend_path (#103701) Clarify sub directories used by pkgutil.extend_path in the docs and the docstring files: M Doc/library/pkgutil.rst M Lib/pkgutil.py diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst index 788a02dcb892..66d753bd1a3c 100644 --- a/Doc/library/pkgutil.rst +++ b/Doc/library/pkgutil.rst @@ -25,9 +25,9 @@ support. from pkgutil import extend_path __path__ = extend_path(__path__, __name__) - This will add to the package's ``__path__`` all subdirectories of directories - on :data:`sys.path` named after the package. This is useful if one wants to - distribute different parts of a single logical package as multiple + For each directory on :data:`sys.path` that has a subdirectory that matches the + package name, add the subdirectory to the package's :attr:`__path__`. This is useful + if one wants to distribute different parts of a single logical package as multiple directories. It also looks for :file:`\*.pkg` files beginning where ``*`` matches the diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py index bdebfd2fc8ac..56731de64af4 100644 --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -511,10 +511,10 @@ def extend_path(path, name): from pkgutil import extend_path __path__ = extend_path(__path__, __name__) - This will add to the package's __path__ all subdirectories of - directories on sys.path named after the package. This is useful - if one wants to distribute different parts of a single logical - package as multiple directories. + For each directory on sys.path that has a subdirectory that + matches the package name, add the subdirectory to the package's + __path__. This is useful if one wants to distribute different + parts of a single logical package as multiple directories. It also looks for *.pkg files beginning where * matches the name argument. This feature is similar to *.pth files (see site.py), From webhook-mailer at python.org Sat Apr 22 20:08:34 2023 From: webhook-mailer at python.org (pablogsal) Date: Sun, 23 Apr 2023 00:08:34 -0000 Subject: [Python-checkins] gh-102310: Change error range for invalid bytes literals (#103663) Message-ID: https://github.com/python/cpython/commit/0fd38917582aae0728e20d8a641e56d9be9270c7 commit: 0fd38917582aae0728e20d8a641e56d9be9270c7 branch: main author: Nikita Sobolev committer: pablogsal date: 2023-04-22T18:08:27-06:00 summary: gh-102310: Change error range for invalid bytes literals (#103663) files: A Misc/NEWS.d/next/Core and Builtins/2023-04-21-17-03-14.gh-issue-102310.anLjDx.rst M Lib/test/test_syntax.py M Parser/string_parser.c diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index f23653558a91..f959bbb44007 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -1853,6 +1853,30 @@ def f(x: *b) Traceback (most recent call last): ... SyntaxError: invalid syntax + +Invalid bytes literals: + + >>> b"?" + Traceback (most recent call last): + ... + b"?" + ^^^ + SyntaxError: bytes can only contain ASCII literal characters + + >>> b"??????" + Traceback (most recent call last): + ... + b"??????" + ^^^^^^^^ + SyntaxError: bytes can only contain ASCII literal characters + + >>> b"abc ?????" # first 3 letters are ascii + Traceback (most recent call last): + ... + b"abc ?????" + ^^^^^^^^^^^ + SyntaxError: bytes can only contain ASCII literal characters + """ import re diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-21-17-03-14.gh-issue-102310.anLjDx.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-21-17-03-14.gh-issue-102310.anLjDx.rst new file mode 100644 index 000000000000..15cb6c64adba --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-21-17-03-14.gh-issue-102310.anLjDx.rst @@ -0,0 +1 @@ +Change the error range for invalid bytes literals. diff --git a/Parser/string_parser.c b/Parser/string_parser.c index be5f0c4a60a6..d4ce33850f7c 100644 --- a/Parser/string_parser.c +++ b/Parser/string_parser.c @@ -248,7 +248,8 @@ _PyPegen_parse_string(Parser *p, Token *t) const char *ch; for (ch = s; *ch; ch++) { if (Py_CHARMASK(*ch) >= 0x80) { - RAISE_SYNTAX_ERROR( + RAISE_SYNTAX_ERROR_KNOWN_LOCATION( + t, "bytes can only contain ASCII " "literal characters"); return NULL; From webhook-mailer at python.org Sun Apr 23 00:41:30 2023 From: webhook-mailer at python.org (orsenthil) Date: Sun, 23 Apr 2023 04:41:30 -0000 Subject: [Python-checkins] gh-81403: Fix for CacheFTPHandler in urllib (#13951) Message-ID: https://github.com/python/cpython/commit/e38bebb9ee805df6848f42845e71c8da8a821ad3 commit: e38bebb9ee805df6848f42845e71c8da8a821ad3 branch: main author: Dan Hemberger <846186+hemberger at users.noreply.github.com> committer: orsenthil date: 2023-04-22T21:41:23-07:00 summary: gh-81403: Fix for CacheFTPHandler in urllib (#13951) bpo-37222: Fix for CacheFTPHandler in urllib A call to FTP.ntransfercmd must be followed by FTP.voidresp to clear the "end transfer" message. Without this, the client and server get out of sync, which will result in an error if the FTP instance is reused to open a second URL. This scenario occurs for even the most basic usage of CacheFTPHandler. Reverts the patch merged as a resolution to bpo-16270 and adds a test case for the CacheFTPHandler in test_urllib2net.py. Co-authored-by: Senthil Kumaran files: M Lib/test/test_urllib2net.py M Lib/urllib/request.py diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py index 5da41c37bbfb..d8d882b2d335 100644 --- a/Lib/test/test_urllib2net.py +++ b/Lib/test/test_urllib2net.py @@ -134,7 +134,9 @@ def setUp(self): # They do sometimes catch some major disasters, though. def test_ftp(self): + # Testing the same URL twice exercises the caching in CacheFTPHandler urls = [ + 'ftp://www.pythontest.net/README', 'ftp://www.pythontest.net/README', ('ftp://www.pythontest.net/non-existent-file', None, urllib.error.URLError), diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index 19e2e5bd3356..5314b3f26021 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -2475,7 +2475,13 @@ def retrfile(self, file, type): return (ftpobj, retrlen) def endtransfer(self): + if not self.busy: + return self.busy = 0 + try: + self.ftp.voidresp() + except ftperrors(): + pass def close(self): self.keepalive = False From webhook-mailer at python.org Sun Apr 23 04:57:17 2023 From: webhook-mailer at python.org (CAM-Gerlach) Date: Sun, 23 Apr 2023 08:57:17 -0000 Subject: [Python-checkins] [3.11] gh-68654: Clarify subdirectories used by pkgutil.extend_path (GH-103701) Message-ID: https://github.com/python/cpython/commit/a43dbe13e2827464afe06e4b73f461003de28d79 commit: a43dbe13e2827464afe06e4b73f461003de28d79 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: CAM-Gerlach date: 2023-04-23T02:57:10-06:00 summary: [3.11] gh-68654: Clarify subdirectories used by pkgutil.extend_path (GH-103701) gh-68654: Clarify subdirectories used by pkgutil.extend_path (GH-103701) Clarify sub directories used by pkgutil.extend_path in the docs and the docstring (cherry picked from commit 7bf94568a9a4101c72b8bf555a811028e5b45ced) Co-authored-by: Randy <69558016+san-juan1667 at users.noreply.github.com> files: M Doc/library/pkgutil.rst M Lib/pkgutil.py diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst index 788a02dcb892..66d753bd1a3c 100644 --- a/Doc/library/pkgutil.rst +++ b/Doc/library/pkgutil.rst @@ -25,9 +25,9 @@ support. from pkgutil import extend_path __path__ = extend_path(__path__, __name__) - This will add to the package's ``__path__`` all subdirectories of directories - on :data:`sys.path` named after the package. This is useful if one wants to - distribute different parts of a single logical package as multiple + For each directory on :data:`sys.path` that has a subdirectory that matches the + package name, add the subdirectory to the package's :attr:`__path__`. This is useful + if one wants to distribute different parts of a single logical package as multiple directories. It also looks for :file:`\*.pkg` files beginning where ``*`` matches the diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py index bdebfd2fc8ac..56731de64af4 100644 --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -511,10 +511,10 @@ def extend_path(path, name): from pkgutil import extend_path __path__ = extend_path(__path__, __name__) - This will add to the package's __path__ all subdirectories of - directories on sys.path named after the package. This is useful - if one wants to distribute different parts of a single logical - package as multiple directories. + For each directory on sys.path that has a subdirectory that + matches the package name, add the subdirectory to the package's + __path__. This is useful if one wants to distribute different + parts of a single logical package as multiple directories. It also looks for *.pkg files beginning where * matches the name argument. This feature is similar to *.pth files (see site.py), From webhook-mailer at python.org Sun Apr 23 08:20:41 2023 From: webhook-mailer at python.org (orsenthil) Date: Sun, 23 Apr 2023 12:20:41 -0000 Subject: [Python-checkins] [3.11] gh-81403: Fix for CacheFTPHandler in urllib (GH-13951) (#103705) Message-ID: https://github.com/python/cpython/commit/6e25228b2e8bd9556b879c629ee20876271bf7da commit: 6e25228b2e8bd9556b879c629ee20876271bf7da branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: orsenthil date: 2023-04-23T05:20:34-07:00 summary: [3.11] gh-81403: Fix for CacheFTPHandler in urllib (GH-13951) (#103705) * gh-81403: Fix for CacheFTPHandler in urllib (GH-13951) bpo-37222: Fix for CacheFTPHandler in urllib A call to FTP.ntransfercmd must be followed by FTP.voidresp to clear the "end transfer" message. Without this, the client and server get out of sync, which will result in an error if the FTP instance is reused to open a second URL. This scenario occurs for even the most basic usage of CacheFTPHandler. Reverts the patch merged as a resolution to bpo-16270 and adds a test case for the CacheFTPHandler in test_urllib2net.py. (cherry picked from commit e38bebb9ee805df6848f42845e71c8da8a821ad3) Co-authored-by: Dan Hemberger <846186+hemberger at users.noreply.github.com> Co-authored-by: Senthil Kumaran * Added NEWS entry. --------- Co-authored-by: Dan Hemberger <846186+hemberger at users.noreply.github.com> Co-authored-by: Senthil Kumaran files: A Misc/NEWS.d/next/Library/2023-04-22-22-14-09.gh-issue-81403.zVz9Td.rst M Lib/test/test_urllib2net.py M Lib/urllib/request.py diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py index 5da41c37bbfb..d8d882b2d335 100644 --- a/Lib/test/test_urllib2net.py +++ b/Lib/test/test_urllib2net.py @@ -134,7 +134,9 @@ def setUp(self): # They do sometimes catch some major disasters, though. def test_ftp(self): + # Testing the same URL twice exercises the caching in CacheFTPHandler urls = [ + 'ftp://www.pythontest.net/README', 'ftp://www.pythontest.net/README', ('ftp://www.pythontest.net/non-existent-file', None, urllib.error.URLError), diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index 73ad0127ecc9..24911bb0190b 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -2469,7 +2469,13 @@ def retrfile(self, file, type): return (ftpobj, retrlen) def endtransfer(self): + if not self.busy: + return self.busy = 0 + try: + self.ftp.voidresp() + except ftperrors(): + pass def close(self): self.keepalive = False diff --git a/Misc/NEWS.d/next/Library/2023-04-22-22-14-09.gh-issue-81403.zVz9Td.rst b/Misc/NEWS.d/next/Library/2023-04-22-22-14-09.gh-issue-81403.zVz9Td.rst new file mode 100644 index 000000000000..6adb71f76772 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-22-22-14-09.gh-issue-81403.zVz9Td.rst @@ -0,0 +1,3 @@ +:class:`urllib.request.CacheFTPHandler` no longer raises :class:`URLError` +if a cached FTP instance is reused. ftplib's endtransfer method calls +voidresp to drain the connection to handle FTP instance reuse properly. From webhook-mailer at python.org Sun Apr 23 10:33:46 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sun, 23 Apr 2023 14:33:46 -0000 Subject: [Python-checkins] GH-103699: Add `__orig_bases__` to various typing classes (#103698) Message-ID: https://github.com/python/cpython/commit/0056701aa370553636b676cc99e327137d1688c6 commit: 0056701aa370553636b676cc99e327137d1688c6 branch: main author: Adrian Garcia Badaracco <1755071+adriangb at users.noreply.github.com> committer: AlexWaygood date: 2023-04-23T08:33:39-06:00 summary: GH-103699: Add `__orig_bases__` to various typing classes (#103698) Co-authored-by: Alex Waygood Co-authored-by: Jelle Zijlstra files: A Misc/NEWS.d/next/Library/2023-04-22-22-37-39.gh-issue-103699.NizCjc.rst M Lib/test/test_typing.py M Lib/typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index f983efe956f9..715710be9e86 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -6695,6 +6695,22 @@ def test_copy_and_pickle(self): self.assertEqual(jane2, jane) self.assertIsInstance(jane2, cls) + def test_orig_bases(self): + T = TypeVar('T') + + class SimpleNamedTuple(NamedTuple): + pass + + class GenericNamedTuple(NamedTuple, Generic[T]): + pass + + self.assertEqual(SimpleNamedTuple.__orig_bases__, (NamedTuple,)) + self.assertEqual(GenericNamedTuple.__orig_bases__, (NamedTuple, Generic[T])) + + CallNamedTuple = NamedTuple('CallNamedTuple', []) + + self.assertEqual(CallNamedTuple.__orig_bases__, (NamedTuple,)) + class TypedDictTests(BaseTestCase): def test_basics_functional_syntax(self): @@ -7126,6 +7142,49 @@ class TD(TypedDict): self.assertIs(type(a), dict) self.assertEqual(a, {'a': 1}) + def test_orig_bases(self): + T = TypeVar('T') + + class Parent(TypedDict): + pass + + class Child(Parent): + pass + + class OtherChild(Parent): + pass + + class MixedChild(Child, OtherChild, Parent): + pass + + class GenericParent(TypedDict, Generic[T]): + pass + + class GenericChild(GenericParent[int]): + pass + + class OtherGenericChild(GenericParent[str]): + pass + + class MixedGenericChild(GenericChild, OtherGenericChild, GenericParent[float]): + pass + + class MultipleGenericBases(GenericParent[int], GenericParent[float]): + pass + + CallTypedDict = TypedDict('CallTypedDict', {}) + + self.assertEqual(Parent.__orig_bases__, (TypedDict,)) + self.assertEqual(Child.__orig_bases__, (Parent,)) + self.assertEqual(OtherChild.__orig_bases__, (Parent,)) + self.assertEqual(MixedChild.__orig_bases__, (Child, OtherChild, Parent,)) + self.assertEqual(GenericParent.__orig_bases__, (TypedDict, Generic[T])) + self.assertEqual(GenericChild.__orig_bases__, (GenericParent[int],)) + self.assertEqual(OtherGenericChild.__orig_bases__, (GenericParent[str],)) + self.assertEqual(MixedGenericChild.__orig_bases__, (GenericChild, OtherGenericChild, GenericParent[float])) + self.assertEqual(MultipleGenericBases.__orig_bases__, (GenericParent[int], GenericParent[float])) + self.assertEqual(CallTypedDict.__orig_bases__, (TypedDict,)) + class RequiredTests(BaseTestCase): diff --git a/Lib/typing.py b/Lib/typing.py index 7c165562c2b5..354bc80eb3ab 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2962,7 +2962,9 @@ class Employee(NamedTuple): elif kwargs: raise TypeError("Either list of fields or keywords" " can be provided to NamedTuple, not both") - return _make_nmtuple(typename, fields, module=_caller()) + nt = _make_nmtuple(typename, fields, module=_caller()) + nt.__orig_bases__ = (NamedTuple,) + return nt _NamedTuple = type.__new__(NamedTupleMeta, 'NamedTuple', (), {}) @@ -2994,6 +2996,9 @@ def __new__(cls, name, bases, ns, total=True): tp_dict = type.__new__(_TypedDictMeta, name, (*generic_base, dict), ns) + if not hasattr(tp_dict, '__orig_bases__'): + tp_dict.__orig_bases__ = bases + annotations = {} own_annotations = ns.get('__annotations__', {}) msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" @@ -3104,7 +3109,9 @@ class body be required. # Setting correct module is necessary to make typed dict classes pickleable. ns['__module__'] = module - return _TypedDictMeta(typename, (), ns, total=total) + td = _TypedDictMeta(typename, (), ns, total=total) + td.__orig_bases__ = (TypedDict,) + return td _TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {}) TypedDict.__mro_entries__ = lambda bases: (_TypedDict,) diff --git a/Misc/NEWS.d/next/Library/2023-04-22-22-37-39.gh-issue-103699.NizCjc.rst b/Misc/NEWS.d/next/Library/2023-04-22-22-37-39.gh-issue-103699.NizCjc.rst new file mode 100644 index 000000000000..60547a25a109 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-22-22-37-39.gh-issue-103699.NizCjc.rst @@ -0,0 +1,2 @@ +Add ``__orig_bases__`` to non-generic TypedDicts, call-based TypedDicts, and +call-based NamedTuples. Other TypedDicts and NamedTuples already had the attribute. From webhook-mailer at python.org Sun Apr 23 11:41:19 2023 From: webhook-mailer at python.org (carljm) Date: Sun, 23 Apr 2023 15:41:19 -0000 Subject: [Python-checkins] [3.11] gh-103449: Fix a bug in dataclass docstring generation (GH-103454) (#103599) Message-ID: https://github.com/python/cpython/commit/ec29d0c0916af129eaafb0ad392449ca173309ed commit: ec29d0c0916af129eaafb0ad392449ca173309ed branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: carljm date: 2023-04-23T09:40:52-06:00 summary: [3.11] gh-103449: Fix a bug in dataclass docstring generation (GH-103454) (#103599) files: A Misc/NEWS.d/next/Library/2023-04-11-21-38-39.gh-issue-103449.-nxmhb.rst M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 221ea2ba3e77..a7e0547705ca 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1092,8 +1092,13 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen, if not getattr(cls, '__doc__'): # Create a class doc-string. - cls.__doc__ = (cls.__name__ + - str(inspect.signature(cls)).replace(' -> None', '')) + try: + # In some cases fetching a signature is not possible. + # But, we surely should not fail in this case. + text_sig = str(inspect.signature(cls)).replace(' -> None', '') + except (TypeError, ValueError): + text_sig = '' + cls.__doc__ = (cls.__name__ + text_sig) if match_args: # I could probably compute this once diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index abe02e3b1ab6..1aaa78db4b0a 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -2224,6 +2224,19 @@ class C: self.assertDocStrEqual(C.__doc__, "C(x:collections.deque=)") + def test_docstring_with_no_signature(self): + # See https://github.com/python/cpython/issues/103449 + class Meta(type): + __call__ = dict + class Base(metaclass=Meta): + pass + + @dataclass + class C(Base): + pass + + self.assertDocStrEqual(C.__doc__, "C") + class TestInit(unittest.TestCase): def test_base_has_init(self): diff --git a/Misc/NEWS.d/next/Library/2023-04-11-21-38-39.gh-issue-103449.-nxmhb.rst b/Misc/NEWS.d/next/Library/2023-04-11-21-38-39.gh-issue-103449.-nxmhb.rst new file mode 100644 index 000000000000..0b2b47af1cba --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-11-21-38-39.gh-issue-103449.-nxmhb.rst @@ -0,0 +1 @@ +Fix a bug in doc string generation in :func:`dataclasses.dataclass`. From webhook-mailer at python.org Sun Apr 23 13:18:56 2023 From: webhook-mailer at python.org (corona10) Date: Sun, 23 Apr 2023 17:18:56 -0000 Subject: [Python-checkins] gh-101408: PyObject_GC_Resize should calculate preheader size. (gh-101741) Message-ID: https://github.com/python/cpython/commit/9c3442c0938127788fa59e4ceb80ae78b86fad1d commit: 9c3442c0938127788fa59e4ceb80ae78b86fad1d branch: main author: Dong-hee Na committer: corona10 date: 2023-04-23T11:18:49-06:00 summary: gh-101408: PyObject_GC_Resize should calculate preheader size. (gh-101741) files: A Misc/NEWS.d/next/C API/2023-02-09-23-09-29.gh-issue-101408._paFIF.rst M Modules/gcmodule.c diff --git a/Misc/NEWS.d/next/C API/2023-02-09-23-09-29.gh-issue-101408._paFIF.rst b/Misc/NEWS.d/next/C API/2023-02-09-23-09-29.gh-issue-101408._paFIF.rst new file mode 100644 index 000000000000..172d66163d42 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-02-09-23-09-29.gh-issue-101408._paFIF.rst @@ -0,0 +1,2 @@ +:c:func:`PyObject_GC_Resize` should calculate preheader size if needed. +Patch by Dong-hee Na. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 1d00fc3e7177..966c1e615502 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2361,16 +2361,17 @@ PyVarObject * _PyObject_GC_Resize(PyVarObject *op, Py_ssize_t nitems) { const size_t basicsize = _PyObject_VAR_SIZE(Py_TYPE(op), nitems); + const size_t presize = _PyType_PreHeaderSize(((PyObject *)op)->ob_type); _PyObject_ASSERT((PyObject *)op, !_PyObject_GC_IS_TRACKED(op)); - if (basicsize > (size_t)PY_SSIZE_T_MAX - sizeof(PyGC_Head)) { + if (basicsize > (size_t)PY_SSIZE_T_MAX - presize) { return (PyVarObject *)PyErr_NoMemory(); } - - PyGC_Head *g = AS_GC(op); - g = (PyGC_Head *)PyObject_Realloc(g, sizeof(PyGC_Head) + basicsize); - if (g == NULL) + char *mem = (char *)op - presize; + mem = (char *)PyObject_Realloc(mem, presize + basicsize); + if (mem == NULL) { return (PyVarObject *)PyErr_NoMemory(); - op = (PyVarObject *) FROM_GC(g); + } + op = (PyVarObject *) (mem + presize); Py_SET_SIZE(op, nitems); return op; } From webhook-mailer at python.org Sun Apr 23 13:19:23 2023 From: webhook-mailer at python.org (corona10) Date: Sun, 23 Apr 2023 17:19:23 -0000 Subject: [Python-checkins] gh-103716: Add test support requires fork in simple_subprocess (gh-103717) Message-ID: https://github.com/python/cpython/commit/777bdff0ec4c21176ddf61e07bc75d170bc65d54 commit: 777bdff0ec4c21176ddf61e07bc75d170bc65d54 branch: main author: Ankit Kumar Pandey <93041495+itsankitkp at users.noreply.github.com> committer: corona10 date: 2023-04-23T11:19:16-06:00 summary: gh-103716: Add test support requires fork in simple_subprocess (gh-103717) add requires fork as test case depends on this files: M Lib/test/test_socketserver.py diff --git a/Lib/test/test_socketserver.py b/Lib/test/test_socketserver.py index 2fa506942332..71ed4c7d58da 100644 --- a/Lib/test/test_socketserver.py +++ b/Lib/test/test_socketserver.py @@ -56,7 +56,7 @@ class ForkingUnixDatagramServer(socketserver.ForkingMixIn, socketserver.UnixDatagramServer): pass - + at test.support.requires_fork() @contextlib.contextmanager def simple_subprocess(testcase): """Tests that a custom child process is not waited on (Issue 1540386)""" From webhook-mailer at python.org Sun Apr 23 13:50:33 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sun, 23 Apr 2023 17:50:33 -0000 Subject: [Python-checkins] gh-103592: Add tests of `Literal` with `Enum` and `Union` of `Literal`s (#103706) Message-ID: https://github.com/python/cpython/commit/5041c2ba6e9c992d1c54834481c9be64581c0235 commit: 5041c2ba6e9c992d1c54834481c9be64581c0235 branch: main author: Nikita Sobolev committer: AlexWaygood date: 2023-04-23T11:50:23-06:00 summary: gh-103592: Add tests of `Literal` with `Enum` and `Union` of `Literal`s (#103706) files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 715710be9e86..b78ce1e43630 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1789,6 +1789,30 @@ def Elem(*args): Union[Elem, str] # Nor should this + def test_union_of_literals(self): + self.assertEqual(Union[Literal[1], Literal[2]].__args__, + (Literal[1], Literal[2])) + self.assertEqual(Union[Literal[1], Literal[1]], + Literal[1]) + + self.assertEqual(Union[Literal[False], Literal[0]].__args__, + (Literal[False], Literal[0])) + self.assertEqual(Union[Literal[True], Literal[1]].__args__, + (Literal[True], Literal[1])) + + import enum + class Ints(enum.IntEnum): + A = 0 + B = 1 + + self.assertEqual(Union[Literal[Ints.A], Literal[Ints.B]].__args__, + (Literal[Ints.A], Literal[Ints.B])) + + self.assertEqual(Union[Literal[0], Literal[Ints.A], Literal[False]].__args__, + (Literal[0], Literal[Ints.A], Literal[False])) + self.assertEqual(Union[Literal[1], Literal[Ints.B], Literal[True]].__args__, + (Literal[1], Literal[Ints.B], Literal[True])) + class TupleTests(BaseTestCase): @@ -2156,6 +2180,13 @@ def test_basics(self): Literal[Literal[1, 2], Literal[4, 5]] Literal[b"foo", u"bar"] + def test_enum(self): + import enum + class My(enum.Enum): + A = 'A' + + self.assertEqual(Literal[My.A].__args__, (My.A,)) + def test_illegal_parameters_do_not_raise_runtime_errors(self): # Type checkers should reject these types, but we do not # raise errors at runtime to maintain maximum flexibility. @@ -2245,6 +2276,20 @@ def test_flatten(self): self.assertEqual(l, Literal[1, 2, 3]) self.assertEqual(l.__args__, (1, 2, 3)) + def test_does_not_flatten_enum(self): + import enum + class Ints(enum.IntEnum): + A = 1 + B = 2 + + l = Literal[ + Literal[Ints.A], + Literal[Ints.B], + Literal[1], + Literal[2], + ] + self.assertEqual(l.__args__, (Ints.A, Ints.B, 1, 2)) + XK = TypeVar('XK', str, bytes) XV = TypeVar('XV') From webhook-mailer at python.org Sun Apr 23 14:15:31 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sun, 23 Apr 2023 18:15:31 -0000 Subject: [Python-checkins] [3.11] gh-103592: Add tests of `Literal` with `Enum` and `Union` of `Literal`s (GH-103706) (#103720) Message-ID: https://github.com/python/cpython/commit/4e9635e2b110b4d0d38d8e839e9604075b43a7f4 commit: 4e9635e2b110b4d0d38d8e839e9604075b43a7f4 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: AlexWaygood date: 2023-04-23T12:15:24-06:00 summary: [3.11] gh-103592: Add tests of `Literal` with `Enum` and `Union` of `Literal`s (GH-103706) (#103720) gh-103592: Add tests of `Literal` with `Enum` and `Union` of `Literal`s (GH-103706) (cherry picked from commit 5041c2ba6e9c992d1c54834481c9be64581c0235) Co-authored-by: Nikita Sobolev files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index be804f1699a0..5eb6d28d78c8 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1784,6 +1784,30 @@ def Elem(*args): Union[Elem, str] # Nor should this + def test_union_of_literals(self): + self.assertEqual(Union[Literal[1], Literal[2]].__args__, + (Literal[1], Literal[2])) + self.assertEqual(Union[Literal[1], Literal[1]], + Literal[1]) + + self.assertEqual(Union[Literal[False], Literal[0]].__args__, + (Literal[False], Literal[0])) + self.assertEqual(Union[Literal[True], Literal[1]].__args__, + (Literal[True], Literal[1])) + + import enum + class Ints(enum.IntEnum): + A = 0 + B = 1 + + self.assertEqual(Union[Literal[Ints.A], Literal[Ints.B]].__args__, + (Literal[Ints.A], Literal[Ints.B])) + + self.assertEqual(Union[Literal[0], Literal[Ints.A], Literal[False]].__args__, + (Literal[0], Literal[Ints.A], Literal[False])) + self.assertEqual(Union[Literal[1], Literal[Ints.B], Literal[True]].__args__, + (Literal[1], Literal[Ints.B], Literal[True])) + class TupleTests(BaseTestCase): @@ -2151,6 +2175,13 @@ def test_basics(self): Literal[Literal[1, 2], Literal[4, 5]] Literal[b"foo", u"bar"] + def test_enum(self): + import enum + class My(enum.Enum): + A = 'A' + + self.assertEqual(Literal[My.A].__args__, (My.A,)) + def test_illegal_parameters_do_not_raise_runtime_errors(self): # Type checkers should reject these types, but we do not # raise errors at runtime to maintain maximum flexibility. @@ -2240,6 +2271,20 @@ def test_flatten(self): self.assertEqual(l, Literal[1, 2, 3]) self.assertEqual(l.__args__, (1, 2, 3)) + def test_does_not_flatten_enum(self): + import enum + class Ints(enum.IntEnum): + A = 1 + B = 2 + + l = Literal[ + Literal[Ints.A], + Literal[Ints.B], + Literal[1], + Literal[2], + ] + self.assertEqual(l.__args__, (Ints.A, Ints.B, 1, 2)) + XK = TypeVar('XK', str, bytes) XV = TypeVar('XV') From webhook-mailer at python.org Sun Apr 23 15:06:17 2023 From: webhook-mailer at python.org (lysnikolaou) Date: Sun, 23 Apr 2023 19:06:17 -0000 Subject: [Python-checkins] GH-103718: Correctly cache and restore f-string buffers when needed (GH-103719) Message-ID: https://github.com/python/cpython/commit/05b3ce7339b9ce44eec728e88e80ba1f125436ed commit: 05b3ce7339b9ce44eec728e88e80ba1f125436ed branch: main author: Lysandros Nikolaou committer: lysnikolaou date: 2023-04-23T13:06:10-06:00 summary: GH-103718: Correctly cache and restore f-string buffers when needed (GH-103719) files: M Lib/test/test_fstring.py M Parser/tokenizer.c M Parser/tokenizer.h diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 0e71de85f16b..b26b12d369f6 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -1532,5 +1532,10 @@ def test_syntax_error_for_starred_expressions(self): "f-string: expecting a valid expression after '{'"): compile("f'{**a}'", "?", "exec") + def test_not_closing_quotes(self): + self.assertAllRaise(SyntaxError, "unterminated f-string literal", ['f"', "f'"]) + self.assertAllRaise(SyntaxError, "unterminated triple-quoted f-string literal", + ['f"""', "f'''"]) + if __name__ == '__main__': unittest.main() diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index f992e55dcac4..0370f75efb53 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -361,21 +361,35 @@ tok_concatenate_interactive_new_line(struct tok_state *tok, const char *line) { return 0; } - -/* Traverse and update all f-string buffers with the value */ +/* Traverse and remember all f-string buffers, in order to be able to restore + them after reallocating tok->buf */ static void -update_fstring_buffers(struct tok_state *tok, char value, int regular, int multiline) +remember_fstring_buffers(struct tok_state *tok) { int index; tokenizer_mode *mode; for (index = tok->tok_mode_stack_index; index >= 0; --index) { mode = &(tok->tok_mode_stack[index]); - if (regular && mode->f_string_start != NULL) { - mode->f_string_start += value; + if (mode->kind == TOK_FSTRING_MODE) { + mode->f_string_start_offset = mode->f_string_start - tok->buf; + mode->f_string_multi_line_start_offset = mode->f_string_multi_line_start - tok->buf; } - if (multiline && mode->f_string_multi_line_start != NULL) { - mode->f_string_multi_line_start += value; + } +} + +/* Traverse and restore all f-string buffers after reallocating tok->buf */ +static void +restore_fstring_buffers(struct tok_state *tok) +{ + int index; + tokenizer_mode *mode; + + for (index = tok->tok_mode_stack_index; index >= 0; --index) { + mode = &(tok->tok_mode_stack[index]); + if (mode->kind == TOK_FSTRING_MODE) { + mode->f_string_start = tok->buf + mode->f_string_start_offset; + mode->f_string_multi_line_start = tok->buf + mode->f_string_multi_line_start_offset; } } } @@ -476,7 +490,7 @@ tok_reserve_buf(struct tok_state *tok, Py_ssize_t size) Py_ssize_t start = tok->start == NULL ? -1 : tok->start - tok->buf; Py_ssize_t line_start = tok->start == NULL ? -1 : tok->line_start - tok->buf; Py_ssize_t multi_line_start = tok->multi_line_start - tok->buf; - update_fstring_buffers(tok, -*tok->buf, /*regular=*/1, /*multiline=*/1); + remember_fstring_buffers(tok); newbuf = (char *)PyMem_Realloc(newbuf, newsize); if (newbuf == NULL) { tok->done = E_NOMEM; @@ -489,7 +503,7 @@ tok_reserve_buf(struct tok_state *tok, Py_ssize_t size) tok->start = start < 0 ? NULL : tok->buf + start; tok->line_start = line_start < 0 ? NULL : tok->buf + line_start; tok->multi_line_start = multi_line_start < 0 ? NULL : tok->buf + multi_line_start; - update_fstring_buffers(tok, *tok->buf, /*regular=*/1, /*multiline=*/1); + restore_fstring_buffers(tok); } return 1; } @@ -1051,7 +1065,7 @@ tok_underflow_interactive(struct tok_state *tok) { } else if (tok->start != NULL) { Py_ssize_t cur_multi_line_start = tok->multi_line_start - tok->buf; - update_fstring_buffers(tok, -*tok->buf, /*regular=*/0, /*multiline=*/1); + remember_fstring_buffers(tok); size_t size = strlen(newtok); ADVANCE_LINENO(); if (!tok_reserve_buf(tok, size + 1)) { @@ -1064,7 +1078,7 @@ tok_underflow_interactive(struct tok_state *tok) { PyMem_Free(newtok); tok->inp += size; tok->multi_line_start = tok->buf + cur_multi_line_start; - update_fstring_buffers(tok, *tok->buf, /*regular=*/0, /*multiline=*/1); + restore_fstring_buffers(tok); } else { ADVANCE_LINENO(); @@ -2207,6 +2221,8 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t the_current_tok->f_string_quote_size = quote_size; the_current_tok->f_string_start = tok->start; the_current_tok->f_string_multi_line_start = tok->line_start; + the_current_tok->f_string_start_offset = -1; + the_current_tok->f_string_multi_line_start_offset = -1; the_current_tok->last_expr_buffer = NULL; the_current_tok->last_expr_size = 0; the_current_tok->last_expr_end = -1; diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h index b75e4e8293d3..2b94aecce626 100644 --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -52,6 +52,9 @@ typedef struct _tokenizer_mode { const char* f_string_start; const char* f_string_multi_line_start; + Py_ssize_t f_string_start_offset; + Py_ssize_t f_string_multi_line_start_offset; + Py_ssize_t last_expr_size; Py_ssize_t last_expr_end; char* last_expr_buffer; From webhook-mailer at python.org Sun Apr 23 15:24:37 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sun, 23 Apr 2023 19:24:37 -0000 Subject: [Python-checkins] gh-101688: Implement types.get_original_bases (#101827) Message-ID: https://github.com/python/cpython/commit/730bbddfdf610343a2e132b0312d12254c3c73d6 commit: 730bbddfdf610343a2e132b0312d12254c3c73d6 branch: main author: James Hilton-Balfe committer: AlexWaygood date: 2023-04-23T20:24:30+01:00 summary: gh-101688: Implement types.get_original_bases (#101827) Co-authored-by: Alex Waygood files: A Misc/NEWS.d/next/Library/2023-02-11-15-01-32.gh-issue-101688.kwXmfM.rst M Doc/library/types.rst M Doc/reference/datamodel.rst M Doc/whatsnew/3.12.rst M Lib/test/test_types.py M Lib/types.py diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 27b984632591..54887f4c5198 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -82,6 +82,46 @@ Dynamic Type Creation .. versionadded:: 3.7 +.. function:: get_original_bases(cls, /) + + Return the tuple of objects originally given as the bases of *cls* before + the :meth:`~object.__mro_entries__` method has been called on any bases + (following the mechanisms laid out in :pep:`560`). This is useful for + introspecting :ref:`Generics `. + + For classes that have an ``__orig_bases__`` attribute, this + function returns the value of ``cls.__orig_bases__``. + For classes without the ``__orig_bases__`` attribute, ``cls.__bases__`` is + returned. + + Examples:: + + from typing import TypeVar, Generic, NamedTuple, TypedDict + + T = TypeVar("T") + class Foo(Generic[T]): ... + class Bar(Foo[int], float): ... + class Baz(list[str]): ... + Eggs = NamedTuple("Eggs", [("a", int), ("b", str)]) + Spam = TypedDict("Spam", {"a": int, "b": str}) + + assert Bar.__bases__ == (Foo, float) + assert get_original_bases(Bar) == (Foo[int], float) + + assert Baz.__bases__ == (list,) + assert get_original_bases(Baz) == (list[str],) + + assert Eggs.__bases__ == (tuple,) + assert get_original_bases(Eggs) == (NamedTuple,) + + assert Spam.__bases__ == (dict,) + assert get_original_bases(Spam) == (TypedDict,) + + assert int.__bases__ == (object,) + assert get_original_bases(int) == (object,) + + .. versionadded:: 3.12 + .. seealso:: :pep:`560` - Core support for typing module and generic types diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 9f91ade35e50..55431f1951e5 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -2102,6 +2102,10 @@ Resolving MRO entries :func:`types.resolve_bases` Dynamically resolve bases that are not instances of :class:`type`. + :func:`types.get_original_bases` + Retrieve a class's "original bases" prior to modifications by + :meth:`~object.__mro_entries__`. + :pep:`560` Core support for typing module and generic types. diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index b98b7151a321..d16c496eb910 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -407,6 +407,13 @@ threading profiling functions in all running threads in addition to the calling one. (Contributed by Pablo Galindo in :gh:`93503`.) +types +----- + +* Add :func:`types.get_original_bases` to allow for further introspection of + :ref:`user-defined-generics` when subclassed. (Contributed by + James Hilton-Balfe and Alex Waygood in :gh:`101827`.) + unicodedata ----------- diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index af095632a36f..9fe5812a14e1 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -1360,6 +1360,67 @@ class C: pass D = types.new_class('D', (A(), C, B()), {}) self.assertEqual(D.__bases__, (A1, A2, A3, C, B1, B2)) + def test_get_original_bases(self): + T = typing.TypeVar('T') + class A: pass + class B(typing.Generic[T]): pass + class C(B[int]): pass + class D(B[str], float): pass + self.assertEqual(types.get_original_bases(A), (object,)) + self.assertEqual(types.get_original_bases(B), (typing.Generic[T],)) + self.assertEqual(types.get_original_bases(C), (B[int],)) + self.assertEqual(types.get_original_bases(int), (object,)) + self.assertEqual(types.get_original_bases(D), (B[str], float)) + + class E(list[T]): pass + class F(list[int]): pass + + self.assertEqual(types.get_original_bases(E), (list[T],)) + self.assertEqual(types.get_original_bases(F), (list[int],)) + + class ClassBasedNamedTuple(typing.NamedTuple): + x: int + + class GenericNamedTuple(typing.NamedTuple, typing.Generic[T]): + x: T + + CallBasedNamedTuple = typing.NamedTuple("CallBasedNamedTuple", [("x", int)]) + + self.assertIs( + types.get_original_bases(ClassBasedNamedTuple)[0], typing.NamedTuple + ) + self.assertEqual( + types.get_original_bases(GenericNamedTuple), + (typing.NamedTuple, typing.Generic[T]) + ) + self.assertIs( + types.get_original_bases(CallBasedNamedTuple)[0], typing.NamedTuple + ) + + class ClassBasedTypedDict(typing.TypedDict): + x: int + + class GenericTypedDict(typing.TypedDict, typing.Generic[T]): + x: T + + CallBasedTypedDict = typing.TypedDict("CallBasedTypedDict", {"x": int}) + + self.assertIs( + types.get_original_bases(ClassBasedTypedDict)[0], + typing.TypedDict + ) + self.assertEqual( + types.get_original_bases(GenericTypedDict), + (typing.TypedDict, typing.Generic[T]) + ) + self.assertIs( + types.get_original_bases(CallBasedTypedDict)[0], + typing.TypedDict + ) + + with self.assertRaisesRegex(TypeError, "Expected an instance of type"): + types.get_original_bases(object()) + # Many of the following tests are derived from test_descr.py def test_prepare_class(self): # Basic test of metaclass derivation diff --git a/Lib/types.py b/Lib/types.py index aa8a1c847223..6110e6e1de72 100644 --- a/Lib/types.py +++ b/Lib/types.py @@ -143,6 +143,38 @@ def _calculate_meta(meta, bases): "of the metaclasses of all its bases") return winner + +def get_original_bases(cls, /): + """Return the class's "original" bases prior to modification by `__mro_entries__`. + + Examples:: + + from typing import TypeVar, Generic, NamedTuple, TypedDict + + T = TypeVar("T") + class Foo(Generic[T]): ... + class Bar(Foo[int], float): ... + class Baz(list[str]): ... + Eggs = NamedTuple("Eggs", [("a", int), ("b", str)]) + Spam = TypedDict("Spam", {"a": int, "b": str}) + + assert get_original_bases(Bar) == (Foo[int], float) + assert get_original_bases(Baz) == (list[str],) + assert get_original_bases(Eggs) == (NamedTuple,) + assert get_original_bases(Spam) == (TypedDict,) + assert get_original_bases(int) == (object,) + """ + try: + return cls.__orig_bases__ + except AttributeError: + try: + return cls.__bases__ + except AttributeError: + raise TypeError( + f'Expected an instance of type, not {type(cls).__name__!r}' + ) from None + + class DynamicClassAttribute: """Route attribute access on a class to __getattr__. diff --git a/Misc/NEWS.d/next/Library/2023-02-11-15-01-32.gh-issue-101688.kwXmfM.rst b/Misc/NEWS.d/next/Library/2023-02-11-15-01-32.gh-issue-101688.kwXmfM.rst new file mode 100644 index 000000000000..6df694639314 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-11-15-01-32.gh-issue-101688.kwXmfM.rst @@ -0,0 +1,2 @@ +Implement :func:`types.get_original_bases` to provide further introspection +for types. From webhook-mailer at python.org Sun Apr 23 16:26:21 2023 From: webhook-mailer at python.org (hugovk) Date: Sun, 23 Apr 2023 20:26:21 -0000 Subject: [Python-checkins] [3.11] GH-103484: Fix broken links reported by linkcheck (GH-103608) (#103683) Message-ID: https://github.com/python/cpython/commit/8642fdce8c019a6263683a32ee1648b212fc2721 commit: 8642fdce8c019a6263683a32ee1648b212fc2721 branch: 3.11 author: Rafael Fontenelle committer: hugovk date: 2023-04-23T23:26:15+03:00 summary: [3.11] GH-103484: Fix broken links reported by linkcheck (GH-103608) (#103683) Co-authored-by: ?ric Co-authored-by: Hugo van Kemenade Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> Fix broken links reported by linkcheck (#103608) files: M Doc/conf.py M Doc/distributing/index.rst M Doc/faq/library.rst M Doc/howto/functional.rst M Doc/howto/urllib2.rst M Doc/library/readline.rst M Doc/whatsnew/2.6.rst M Doc/whatsnew/2.7.rst M Misc/NEWS.d/3.7.0b2.rst M Misc/NEWS.d/3.8.0a1.rst M Misc/NEWS.d/3.9.0a1.rst M Misc/NEWS.d/3.9.0a2.rst M Misc/NEWS.d/3.9.0a4.rst diff --git a/Doc/conf.py b/Doc/conf.py index d89470973dac..851b473108d1 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -251,6 +251,24 @@ r'https://github.com/python/cpython/tree/.*': 'https://github.com/python/cpython/blob/.*' } +linkcheck_anchors_ignore = [ + # ignore anchors that start with a '/', e.g. Wikipedia media files: + # https://en.wikipedia.org/wiki/Walrus#/media/File:Pacific_Walrus_-_Bull_(8247646168).jpg + r'\/.*', +] + +linkcheck_ignore = [ + # The crawler gets "Anchor not found" + r'https://developer.apple.com/documentation/.+?#.*', + r'https://devguide.python.org.+?/#.*', + r'https://github.com.+?#.*', + # Robot crawlers not allowed: "403 Client Error: Forbidden" + r'https://support.enthought.com/hc/.*', + # SSLError CertificateError, even though it is valid + r'https://unix.org/version2/whatsnew/lp64_wp.html', +] + + # Options for extensions # ---------------------- diff --git a/Doc/distributing/index.rst b/Doc/distributing/index.rst index 136cf4e77b15..8e70c24e7026 100644 --- a/Doc/distributing/index.rst +++ b/Doc/distributing/index.rst @@ -130,14 +130,10 @@ involved in creating and publishing a project: * `Uploading the project to the Python Package Index`_ * `The .pypirc file`_ -.. _Project structure: \ - https://packaging.python.org/tutorials/packaging-projects/#packaging-python-projects -.. _Building and packaging the project: \ - https://packaging.python.org/tutorials/packaging-projects/#creating-the-package-files -.. _Uploading the project to the Python Package Index: \ - https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives -.. _The .pypirc file: \ - https://packaging.python.org/specifications/pypirc/ +.. _Project structure: https://packaging.python.org/tutorials/packaging-projects/#packaging-python-projects +.. _Building and packaging the project: https://packaging.python.org/tutorials/packaging-projects/#creating-the-package-files +.. _Uploading the project to the Python Package Index: https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives +.. _The .pypirc file: https://packaging.python.org/specifications/pypirc/ How do I...? diff --git a/Doc/faq/library.rst b/Doc/faq/library.rst index a9cde4565750..597caaa778e1 100644 --- a/Doc/faq/library.rst +++ b/Doc/faq/library.rst @@ -780,7 +780,7 @@ socket to :meth:`select.select` to check if it's writable. The :mod:`asyncio` module provides a general purpose single-threaded and concurrent asynchronous library, which can be used for writing non-blocking network code. - The third-party `Twisted `_ library is + The third-party `Twisted `_ library is a popular and feature-rich alternative. diff --git a/Doc/howto/functional.rst b/Doc/howto/functional.rst index e68bc2ebb1cc..64f2293b21e2 100644 --- a/Doc/howto/functional.rst +++ b/Doc/howto/functional.rst @@ -1208,8 +1208,8 @@ General ------- **Structure and Interpretation of Computer Programs**, by Harold Abelson and -Gerald Jay Sussman with Julie Sussman. Full text at -https://mitpress.mit.edu/sicp/. In this classic textbook of computer science, +Gerald Jay Sussman with Julie Sussman. The book can be found at +https://mitpress.mit.edu/sicp. In this classic textbook of computer science, chapters 2 and 3 discuss the use of sequences and streams to organize the data flow inside a program. The book uses Scheme for its examples, but many of the design approaches described in these chapters are applicable to functional-style diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst index 69af3c3a85c5..61ba6bd7224f 100644 --- a/Doc/howto/urllib2.rst +++ b/Doc/howto/urllib2.rst @@ -86,7 +86,7 @@ response:: import urllib.request - req = urllib.request.Request('http://www.voidspace.org.uk') + req = urllib.request.Request('http://python.org/') with urllib.request.urlopen(req) as response: the_page = response.read() @@ -458,7 +458,7 @@ To illustrate creating and installing a handler we will use the ``HTTPBasicAuthHandler``. For a more detailed discussion of this subject -- including an explanation of how Basic Authentication works - see the `Basic Authentication Tutorial -`_. +`__. When authentication is required, the server sends a header (as well as the 401 error code) requesting authentication. This specifies the authentication scheme diff --git a/Doc/library/readline.rst b/Doc/library/readline.rst index 4d485d25b540..8fb0eca8df74 100644 --- a/Doc/library/readline.rst +++ b/Doc/library/readline.rst @@ -19,7 +19,7 @@ function. Readline keybindings may be configured via an initialization file, typically ``.inputrc`` in your home directory. See `Readline Init File -`_ +`_ in the GNU Readline manual for information about the format and allowable constructs of that file, and the capabilities of the Readline library in general. diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 34f2656f765c..4ee2aacb108a 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -172,7 +172,7 @@ this edition of "What's New in Python" links to the bug/patch item for each change. Hosting of the Python bug tracker is kindly provided by -`Upfront Systems `__ +`Upfront Systems `__ of Stellenbosch, South Africa. Martin von L?wis put a lot of effort into importing existing bugs and patches from SourceForge; his scripts for this import operation are at diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index 82f5ea3b3127..1acb09cf9257 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -2103,7 +2103,7 @@ Changes to Python's build process and to the C API include: * The latest release of the GNU Debugger, GDB 7, can be `scripted using Python - `__. + `__. When you begin debugging an executable program P, GDB will look for a file named ``P-gdb.py`` and automatically read it. Dave Malcolm contributed a :file:`python-gdb.py` that adds a number of diff --git a/Misc/NEWS.d/3.7.0b2.rst b/Misc/NEWS.d/3.7.0b2.rst index b2ade206bd5f..9590914599bb 100644 --- a/Misc/NEWS.d/3.7.0b2.rst +++ b/Misc/NEWS.d/3.7.0b2.rst @@ -357,7 +357,7 @@ Wirtel Add TLSVersion constants and SSLContext.maximum_version / minimum_version attributes. The new API wraps OpenSSL 1.1 -https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_min_proto_version.html +https://web.archive.org/web/20180309043602/https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_min_proto_version.html feature. .. diff --git a/Misc/NEWS.d/3.8.0a1.rst b/Misc/NEWS.d/3.8.0a1.rst index d95055a59da3..c9ca4b8404e6 100644 --- a/Misc/NEWS.d/3.8.0a1.rst +++ b/Misc/NEWS.d/3.8.0a1.rst @@ -5951,7 +5951,7 @@ Wirtel Add TLSVersion constants and SSLContext.maximum_version / minimum_version attributes. The new API wraps OpenSSL 1.1 -https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_min_proto_version.html +https://web.archive.org/web/20180309043602/https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_min_proto_version.html feature. .. diff --git a/Misc/NEWS.d/3.9.0a1.rst b/Misc/NEWS.d/3.9.0a1.rst index 63d77fd3ac0c..2525696c58a4 100644 --- a/Misc/NEWS.d/3.9.0a1.rst +++ b/Misc/NEWS.d/3.9.0a1.rst @@ -4887,7 +4887,7 @@ Fix use of registry values to launch Python from Microsoft Store app. .. section: Windows Fix memory leak on Windows in creating an SSLContext object or running -urllib.request.urlopen('https://...'). +``urllib.request.urlopen('https://...')``. .. diff --git a/Misc/NEWS.d/3.9.0a2.rst b/Misc/NEWS.d/3.9.0a2.rst index 226ea0d3df22..a03eb10f1d52 100644 --- a/Misc/NEWS.d/3.9.0a2.rst +++ b/Misc/NEWS.d/3.9.0a2.rst @@ -686,7 +686,7 @@ added. Update documentation to state that to activate virtual environments under fish one should use `source`, not `.` as documented at -https://fishshell.com/docs/current/commands.html#source. +https://fishshell.com/docs/current/cmds/source.html. .. diff --git a/Misc/NEWS.d/3.9.0a4.rst b/Misc/NEWS.d/3.9.0a4.rst index 2aef8b26b016..019b34c4082d 100644 --- a/Misc/NEWS.d/3.9.0a4.rst +++ b/Misc/NEWS.d/3.9.0a4.rst @@ -392,7 +392,7 @@ The distutils ``bdist_msi`` command is deprecated in Python 3.9, use Improved performance of zipfile.Path for files with a large number of entries. Also improved performance and fixed minor issue as published with `importlib_metadata 1.5 -`_. +`_. .. From webhook-mailer at python.org Sun Apr 23 18:58:09 2023 From: webhook-mailer at python.org (orsenthil) Date: Sun, 23 Apr 2023 22:58:09 -0000 Subject: [Python-checkins] gh-81403: Add NEWS entry for PR #13951 (#103729) Message-ID: https://github.com/python/cpython/commit/82932b72cabb6a77bbf5465a0a9574f90773aadf commit: 82932b72cabb6a77bbf5465a0a9574f90773aadf branch: main author: Senthil Kumaran committer: orsenthil date: 2023-04-23T15:58:03-07:00 summary: gh-81403: Add NEWS entry for PR #13951 (#103729) Add NEWS entry for PR #13951 files: A Misc/NEWS.d/next/Library/2023-04-23-15-39-17.gh-issue-81403.zVz9Td.rst diff --git a/Misc/NEWS.d/next/Library/2023-04-23-15-39-17.gh-issue-81403.zVz9Td.rst b/Misc/NEWS.d/next/Library/2023-04-23-15-39-17.gh-issue-81403.zVz9Td.rst new file mode 100644 index 000000000000..6adb71f76772 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-23-15-39-17.gh-issue-81403.zVz9Td.rst @@ -0,0 +1,3 @@ +:class:`urllib.request.CacheFTPHandler` no longer raises :class:`URLError` +if a cached FTP instance is reused. ftplib's endtransfer method calls +voidresp to drain the connection to handle FTP instance reuse properly. From webhook-mailer at python.org Sun Apr 23 19:14:21 2023 From: webhook-mailer at python.org (corona10) Date: Sun, 23 Apr 2023 23:14:21 -0000 Subject: [Python-checkins] gh-103724: Add test case if no arg as provided in os.register_at_fork (gh-103725) Message-ID: https://github.com/python/cpython/commit/7255bbd4a1841447a21c3eb74e4fd9e21818d833 commit: 7255bbd4a1841447a21c3eb74e4fd9e21818d833 branch: main author: Ankit Kumar Pandey <93041495+itsankitkp at users.noreply.github.com> committer: corona10 date: 2023-04-23T17:14:14-06:00 summary: gh-103724: Add test case if no arg as provided in os.register_at_fork (gh-103725) files: M Lib/test/test_posix.py diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index 77f42f7f9c93..444f8abe4607 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -231,6 +231,9 @@ def test_register_at_fork(self): with self.assertRaises(TypeError, msg="Invalid arg was allowed"): # Ensure a combination of valid and invalid is an error. os.register_at_fork(before=None, after_in_parent=lambda: 3) + with self.assertRaises(TypeError, msg="At least one argument is required"): + # when no arg is passed + os.register_at_fork() with self.assertRaises(TypeError, msg="Invalid arg was allowed"): # Ensure a combination of valid and invalid is an error. os.register_at_fork(before=lambda: None, after_in_child='') From webhook-mailer at python.org Sun Apr 23 19:21:34 2023 From: webhook-mailer at python.org (pablogsal) Date: Sun, 23 Apr 2023 23:21:34 -0000 Subject: [Python-checkins] [3.11] gh-102310: Change error range for invalid bytes literals (GH-103663) (#103703) Message-ID: https://github.com/python/cpython/commit/7b2ac6cf3dd33d591d0e14a020c84aa331d29932 commit: 7b2ac6cf3dd33d591d0e14a020c84aa331d29932 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: pablogsal date: 2023-04-23T17:21:27-06:00 summary: [3.11] gh-102310: Change error range for invalid bytes literals (GH-103663) (#103703) files: A Misc/NEWS.d/next/Core and Builtins/2023-04-21-17-03-14.gh-issue-102310.anLjDx.rst M Lib/test/test_syntax.py M Parser/string_parser.c diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index 50168d9200a2..81456d62a37c 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -1803,6 +1803,30 @@ def f(x: *b) Traceback (most recent call last): ... SyntaxError: invalid syntax + +Invalid bytes literals: + + >>> b"?" + Traceback (most recent call last): + ... + b"?" + ^^^ + SyntaxError: bytes can only contain ASCII literal characters + + >>> b"??????" + Traceback (most recent call last): + ... + b"??????" + ^^^^^^^^ + SyntaxError: bytes can only contain ASCII literal characters + + >>> b"abc ?????" # first 3 letters are ascii + Traceback (most recent call last): + ... + b"abc ?????" + ^^^^^^^^^^^ + SyntaxError: bytes can only contain ASCII literal characters + """ import re diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-21-17-03-14.gh-issue-102310.anLjDx.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-21-17-03-14.gh-issue-102310.anLjDx.rst new file mode 100644 index 000000000000..15cb6c64adba --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-21-17-03-14.gh-issue-102310.anLjDx.rst @@ -0,0 +1 @@ +Change the error range for invalid bytes literals. diff --git a/Parser/string_parser.c b/Parser/string_parser.c index 4f3f046673cb..fb2b9808af15 100644 --- a/Parser/string_parser.c +++ b/Parser/string_parser.c @@ -259,7 +259,8 @@ _PyPegen_parsestr(Parser *p, int *bytesmode, int *rawmode, PyObject **result, const char *ch; for (ch = s; *ch; ch++) { if (Py_CHARMASK(*ch) >= 0x80) { - RAISE_SYNTAX_ERROR( + RAISE_SYNTAX_ERROR_KNOWN_LOCATION( + t, "bytes can only contain ASCII " "literal characters"); return -1; From webhook-mailer at python.org Sun Apr 23 19:25:16 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sun, 23 Apr 2023 23:25:16 -0000 Subject: [Python-checkins] gh-103668: Run pyugrade on idlelib (#103671) Message-ID: https://github.com/python/cpython/commit/bd2dca035af88694e25fb060f984fbbcda82bed8 commit: bd2dca035af88694e25fb060f984fbbcda82bed8 branch: main author: Nikita Sobolev committer: terryjreedy date: 2023-04-23T19:25:08-04:00 summary: gh-103668: Run pyugrade on idlelib (#103671) --------- Co-authored-by: Terry Jan Reedy files: M Lib/idlelib/calltip_w.py M Lib/idlelib/debugger.py M Lib/idlelib/debugobj.py M Lib/idlelib/editor.py M Lib/idlelib/filelist.py M Lib/idlelib/idle_test/test_config.py M Lib/idlelib/idle_test/test_outwin.py M Lib/idlelib/multicall.py M Lib/idlelib/outwin.py M Lib/idlelib/pyshell.py M Lib/idlelib/redirector.py M Lib/idlelib/rpc.py M Lib/idlelib/run.py M Lib/idlelib/textview.py M Lib/idlelib/tooltip.py M Lib/idlelib/tree.py M Lib/idlelib/undo.py diff --git a/Lib/idlelib/calltip_w.py b/Lib/idlelib/calltip_w.py index 1e0404aa49f5..278546064add 100644 --- a/Lib/idlelib/calltip_w.py +++ b/Lib/idlelib/calltip_w.py @@ -25,7 +25,7 @@ def __init__(self, text_widget): text_widget: a Text widget with code for which call-tips are desired """ # Note: The Text widget will be accessible as self.anchor_widget - super(CalltipWindow, self).__init__(text_widget) + super().__init__(text_widget) self.label = self.text = None self.parenline = self.parencol = self.lastline = None @@ -54,7 +54,7 @@ def position_window(self): return self.lastline = curline self.anchor_widget.see("insert") - super(CalltipWindow, self).position_window() + super().position_window() def showtip(self, text, parenleft, parenright): """Show the call-tip, bind events which will close it and reposition it. @@ -73,7 +73,7 @@ def showtip(self, text, parenleft, parenright): self.parenline, self.parencol = map( int, self.anchor_widget.index(parenleft).split(".")) - super(CalltipWindow, self).showtip() + super().showtip() self._bind_events() @@ -143,7 +143,7 @@ def hidetip(self): # ValueError may be raised by MultiCall pass - super(CalltipWindow, self).hidetip() + super().hidetip() def _bind_events(self): """Bind event handlers.""" diff --git a/Lib/idlelib/debugger.py b/Lib/idlelib/debugger.py index ccd03e46e161..452c62b42655 100644 --- a/Lib/idlelib/debugger.py +++ b/Lib/idlelib/debugger.py @@ -49,9 +49,9 @@ def __frame2message(self, frame): filename = code.co_filename lineno = frame.f_lineno basename = os.path.basename(filename) - message = "%s:%s" % (basename, lineno) + message = f"{basename}:{lineno}" if code.co_name != "?": - message = "%s: %s()" % (message, code.co_name) + message = f"{message}: {code.co_name}()" return message @@ -213,7 +213,8 @@ def interaction(self, message, frame, info=None): m1 = "%s" % str(type) if value is not None: try: - m1 = "%s: %s" % (m1, str(value)) + # TODO redo entire section, tries not needed. + m1 = f"{m1}: {value}" except: pass bg = "yellow" diff --git a/Lib/idlelib/debugobj.py b/Lib/idlelib/debugobj.py index 5a4c99788420..71d01c7070df 100644 --- a/Lib/idlelib/debugobj.py +++ b/Lib/idlelib/debugobj.py @@ -87,7 +87,7 @@ def GetSubList(self): continue def setfunction(value, key=key, object=self.object): object[key] = value - item = make_objecttreeitem("%r:" % (key,), value, setfunction) + item = make_objecttreeitem(f"{key!r}:", value, setfunction) sublist.append(item) return sublist diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 08d6aa2efde2..505815502600 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -38,12 +38,13 @@ def _sphinx_version(): "Format sys.version_info to produce the Sphinx version string used to install the chm docs" major, minor, micro, level, serial = sys.version_info - release = '%s%s' % (major, minor) - release += '%s' % (micro,) + # TODO remove unneeded function since .chm no longer installed + release = f'{major}{minor}' + release += f'{micro}' if level == 'candidate': - release += 'rc%s' % (serial,) + release += f'rc{serial}' elif level != 'final': - release += '%s%s' % (level[0], serial) + release += f'{level[0]}{serial}' return release @@ -950,7 +951,7 @@ def update_recent_files_list(self, new_file=None): rf_list = [] file_path = self.recent_files_path if file_path and os.path.exists(file_path): - with open(file_path, 'r', + with open(file_path, encoding='utf_8', errors='replace') as rf_list_file: rf_list = rf_list_file.readlines() if new_file: @@ -1458,7 +1459,7 @@ def newline_and_indent_event(self, event): else: self.reindent_to(y.compute_backslash_indent()) else: - assert 0, "bogus continuation type %r" % (c,) + assert 0, f"bogus continuation type {c!r}" return "break" # This line starts a brand new statement; indent relative to diff --git a/Lib/idlelib/filelist.py b/Lib/idlelib/filelist.py index 254f5caf6b81..f87781d2570f 100644 --- a/Lib/idlelib/filelist.py +++ b/Lib/idlelib/filelist.py @@ -22,7 +22,7 @@ def open(self, filename, action=None): # This can happen when bad filename is passed on command line: messagebox.showerror( "File Error", - "%r is a directory." % (filename,), + f"{filename!r} is a directory.", master=self.root) return None key = os.path.normcase(filename) @@ -90,7 +90,7 @@ def filename_changed_edit(self, edit): self.inversedict[conflict] = None messagebox.showerror( "Name Conflict", - "You now have multiple edit windows open for %r" % (filename,), + f"You now have multiple edit windows open for {filename!r}", master=self.root) self.dict[newkey] = edit self.inversedict[edit] = newkey diff --git a/Lib/idlelib/idle_test/test_config.py b/Lib/idlelib/idle_test/test_config.py index 697fda527968..08ed76fe2882 100644 --- a/Lib/idlelib/idle_test/test_config.py +++ b/Lib/idlelib/idle_test/test_config.py @@ -191,7 +191,7 @@ def setUpClass(cls): idle_dir = os.path.abspath(sys.path[0]) for ctype in conf.config_types: config_path = os.path.join(idle_dir, '../config-%s.def' % ctype) - with open(config_path, 'r') as f: + with open(config_path) as f: cls.config_string[ctype] = f.read() cls.orig_warn = config._warn diff --git a/Lib/idlelib/idle_test/test_outwin.py b/Lib/idlelib/idle_test/test_outwin.py index e347bfca7f19..d6e85ad67441 100644 --- a/Lib/idlelib/idle_test/test_outwin.py +++ b/Lib/idlelib/idle_test/test_outwin.py @@ -159,7 +159,7 @@ def test_file_line_helper(self, mock_open): for line, expected_output in test_lines: self.assertEqual(flh(line), expected_output) if expected_output: - mock_open.assert_called_with(expected_output[0], 'r') + mock_open.assert_called_with(expected_output[0]) if __name__ == '__main__': diff --git a/Lib/idlelib/multicall.py b/Lib/idlelib/multicall.py index dc02001292fc..0200f445cc93 100644 --- a/Lib/idlelib/multicall.py +++ b/Lib/idlelib/multicall.py @@ -52,9 +52,9 @@ _modifier_masks = (MC_CONTROL, MC_ALT, MC_SHIFT, MC_META) # a dictionary to map a modifier name into its number -_modifier_names = dict([(name, number) +_modifier_names = {name: number for number in range(len(_modifiers)) - for name in _modifiers[number]]) + for name in _modifiers[number]} # In 3.4, if no shell window is ever open, the underlying Tk widget is # destroyed before .__del__ methods here are called. The following @@ -134,7 +134,7 @@ def nbits(n): return nb statelist = [] for state in states: - substates = list(set(state & x for x in states)) + substates = list({state & x for x in states}) substates.sort(key=nbits, reverse=True) statelist.append(substates) return statelist @@ -258,9 +258,9 @@ def __del__(self): _binder_classes = (_ComplexBinder,) * 4 + (_SimpleBinder,) * (len(_types)-4) # A dictionary to map a type name into its number -_type_names = dict([(name, number) +_type_names = {name: number for number in range(len(_types)) - for name in _types[number]]) + for name in _types[number]} _keysym_re = re.compile(r"^\w+$") _button_re = re.compile(r"^[1-5]$") diff --git a/Lib/idlelib/outwin.py b/Lib/idlelib/outwin.py index 5ab08bbaf4bc..ac67c904ab97 100644 --- a/Lib/idlelib/outwin.py +++ b/Lib/idlelib/outwin.py @@ -42,7 +42,7 @@ def file_line_helper(line): if match: filename, lineno = match.group(1, 2) try: - f = open(filename, "r") + f = open(filename) f.close() break except OSError: diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index e68233a5a413..bdde15616617 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -249,7 +249,7 @@ def store_file_breaks(self): breaks = self.breakpoints filename = self.io.filename try: - with open(self.breakpointPath, "r") as fp: + with open(self.breakpointPath) as fp: lines = fp.readlines() except OSError: lines = [] @@ -279,7 +279,7 @@ def restore_file_breaks(self): if filename is None: return if os.path.isfile(self.breakpointPath): - with open(self.breakpointPath, "r") as fp: + with open(self.breakpointPath) as fp: lines = fp.readlines() for line in lines: if line.startswith(filename + '='): @@ -441,7 +441,7 @@ def build_subprocess_arglist(self): # run from the IDLE source directory. del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc', default=False, type='bool') - command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,) + command = f"__import__('idlelib.run').run.main({del_exitf!r})" return [sys.executable] + w + ["-c", command, str(self.port)] def start_subprocess(self): @@ -574,9 +574,9 @@ def transfer_path(self, with_cwd=False): self.runcommand("""if 1: import sys as _sys - _sys.path = %r + _sys.path = {!r} del _sys - \n""" % (path,)) + \n""".format(path)) active_seq = None @@ -703,14 +703,14 @@ def stuffsource(self, source): def prepend_syspath(self, filename): "Prepend sys.path with file's directory if not already included" self.runcommand("""if 1: - _filename = %r + _filename = {!r} import sys as _sys from os.path import dirname as _dirname _dir = _dirname(_filename) if not _dir in _sys.path: _sys.path.insert(0, _dir) del _filename, _sys, _dirname, _dir - \n""" % (filename,)) + \n""".format(filename)) def showsyntaxerror(self, filename=None): """Override Interactive Interpreter method: Use Colorizing @@ -1536,7 +1536,7 @@ def main(): try: opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:") except getopt.error as msg: - print("Error: %s\n%s" % (msg, usage_msg), file=sys.stderr) + print(f"Error: {msg}\n{usage_msg}", file=sys.stderr) sys.exit(2) for o, a in opts: if o == '-c': @@ -1668,9 +1668,9 @@ def main(): if cmd or script: shell.interp.runcommand("""if 1: import sys as _sys - _sys.argv = %r + _sys.argv = {!r} del _sys - \n""" % (sys.argv,)) + \n""".format(sys.argv)) if cmd: shell.interp.execsource(cmd) elif script: diff --git a/Lib/idlelib/redirector.py b/Lib/idlelib/redirector.py index 9ab34c5acfb2..4928340e98df 100644 --- a/Lib/idlelib/redirector.py +++ b/Lib/idlelib/redirector.py @@ -47,9 +47,8 @@ def __init__(self, widget): tk.createcommand(w, self.dispatch) def __repr__(self): - return "%s(%s<%s>)" % (self.__class__.__name__, - self.widget.__class__.__name__, - self.widget._w) + w = self.widget + return f"{self.__class__.__name__,}({w.__class__.__name__}<{w._w}>)" def close(self): "Unregister operations and revert redirection created by .__init__." @@ -143,8 +142,7 @@ def __init__(self, redir, operation): self.orig_and_operation = (redir.orig, operation) def __repr__(self): - return "%s(%r, %r)" % (self.__class__.__name__, - self.redir, self.operation) + return f"{self.__class__.__name__,}({self.redir!r}, {self.operation!r})" def __call__(self, *args): return self.tk_call(self.orig_and_operation + args) diff --git a/Lib/idlelib/rpc.py b/Lib/idlelib/rpc.py index 62eec84c9c8d..b08b80c90045 100644 --- a/Lib/idlelib/rpc.py +++ b/Lib/idlelib/rpc.py @@ -174,7 +174,7 @@ def localcall(self, seq, request): except TypeError: return ("ERROR", "Bad request format") if oid not in self.objtable: - return ("ERROR", "Unknown object id: %r" % (oid,)) + return ("ERROR", f"Unknown object id: {oid!r}") obj = self.objtable[oid] if methodname == "__methods__": methods = {} @@ -185,7 +185,7 @@ def localcall(self, seq, request): _getattributes(obj, attributes) return ("OK", attributes) if not hasattr(obj, methodname): - return ("ERROR", "Unsupported method name: %r" % (methodname,)) + return ("ERROR", f"Unsupported method name: {methodname!r}") method = getattr(obj, methodname) try: if how == 'CALL': diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 04ce615621ee..84792a82b002 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -52,13 +52,13 @@ def idle_formatwarning(message, category, filename, lineno, line=None): """Format warnings the IDLE way.""" s = "\nWarning (from warnings module):\n" - s += ' File \"%s\", line %s\n' % (filename, lineno) + s += f' File \"{filename}\", line {lineno}\n' if line is None: line = linecache.getline(filename, lineno) line = line.strip() if line: s += " %s\n" % line - s += "%s: %s\n" % (category.__name__, message) + s += f"{category.__name__}: {message}\n" return s def idle_showwarning_subproc( diff --git a/Lib/idlelib/textview.py b/Lib/idlelib/textview.py index a66c1a4309a6..23f0f4cb5027 100644 --- a/Lib/idlelib/textview.py +++ b/Lib/idlelib/textview.py @@ -169,7 +169,7 @@ def view_file(parent, title, filename, encoding, modal=True, wrap='word', with contents of the file. """ try: - with open(filename, 'r', encoding=encoding) as file: + with open(filename, encoding=encoding) as file: contents = file.read() except OSError: showerror(title='File Load Error', diff --git a/Lib/idlelib/tooltip.py b/Lib/idlelib/tooltip.py index d714318dae8e..3983690dd411 100644 --- a/Lib/idlelib/tooltip.py +++ b/Lib/idlelib/tooltip.py @@ -92,7 +92,7 @@ def __init__(self, anchor_widget, hover_delay=1000): e.g. after hovering over the anchor widget with the mouse for enough time. """ - super(OnHoverTooltipBase, self).__init__(anchor_widget) + super().__init__(anchor_widget) self.hover_delay = hover_delay self._after_id = None @@ -107,7 +107,7 @@ def __del__(self): self.anchor_widget.unbind("